Mercurial > hg > release > icedtea6-1.4
changeset 1243:8bf089d06e19
2008-12-02 Omair Majid <omajid@redhat.com>
This patch reduces visibility of classes and prevents inheritance to
reduce any potential security issues. Also adds a few security checks.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java:
Change scope of class and functions from public to package-private.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java:
Likewise.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java:
Likewise.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java:
Likewise.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java:
Likewise.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java:
Change class to be final. Change clip name to 'Audio Clip' and add some
documentation and annotations.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java:
Change class scope to package-private. Add annoatations to functions.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java:
Add override annotations to functions.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java:
Change class to final.
(getLine): Check for audio permissions before returning Ports.
(openRemote): Check for permissions to connect before connecting to a
remote PulseAudio server.
(openImpl): New function. Connect to the PulseAudio server.
(debug): Removed.
(main): Removed
(ThreadWriter): Removed.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java:
Change class to final. Bump version.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java:
(PulseAudioMixerProvider): Removed.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMuteControl.java:
Change class to final. Formatting fixes.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java:
Change class scope to package private. Make constructor package-private.
Add override annotations.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java:
Change class to final. Make constructor package-private. Add override
annotations.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java:
Make class final. Make constructor package-private.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java:
Make class final. Add override annotations
(PulseAudioTargetDataLine): Make constructor package-private.
(fragmentBuffer): Make variable private.
(drained): Likewise.
(flushed): Likewise.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java:
Make class final. Constructor now pacakge-private.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java:
Make class final.
(MIN_VOLUME),
(MAX_VOLUME): Make variables pacakge-private.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java:
Make class final.
(loadNativeLibrary): Make package-private.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java:
Make class final. Change scope of as many functions from public to
package-private as possible.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java:
Make class and all functions package-private.
* pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamSampleSpecification.java:
Make class package-private.
line wrap: on
line diff
--- a/ChangeLog Wed Dec 03 14:31:01 2008 +0000 +++ b/ChangeLog Wed Dec 03 10:07:38 2008 -0500 @@ -1,3 +1,68 @@ +2008-12-02 Omair Majid <omajid@redhat.com> + + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java: + Change scope of class and functions from public to package-private. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java: + Likewise. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java: + Likewise. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java: + Likewise. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java: + Likewise. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java: + Change class to be final. Change clip name to 'Audio Clip' and add some + documentation and annotations. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java: + Change class scope to package-private. Add annoatations to functions. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java: + Add override annotations to functions. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java: + Change class to final. + (getLine): Check for audio permissions before returning Ports. + (openRemote): Check for permissions to connect before connecting to a + remote PulseAudio server. + (openImpl): New function. Connect to the PulseAudio server. + (debug): Removed. + (main): Removed + (ThreadWriter): Removed. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java: + Change class to final. Bump version. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java: + (PulseAudioMixerProvider): Removed. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMuteControl.java: + Change class to final. Formatting fixes. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java: + Change class scope to package private. Make constructor package-private. + Add override annotations. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java: + Change class to final. Make constructor package-private. Add override + annotations. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java: + Make class final. Make constructor package-private. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java: + Make class final. Add override annotations + (PulseAudioTargetDataLine): Make constructor package-private. + (fragmentBuffer): Make variable private. + (drained): Likewise. + (flushed): Likewise. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java: + Make class final. Constructor now pacakge-private. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java: + Make class final. + (MIN_VOLUME), + (MAX_VOLUME): Make variables pacakge-private. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java: + Make class final. + (loadNativeLibrary): Make package-private. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java: + Make class final. Change scope of as many functions from public to + package-private as possible. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java: + Make class and all functions package-private. + * pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamSampleSpecification.java: + Make class package-private. + 2008-12-03 Andrew John Hughes <gnu_andrew@member.fsf.org> Create hierarchical patch space.
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextEvent.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,8 +37,20 @@ package org.classpath.icedtea.pulseaudio; -public class ContextEvent { +/** + * This class encapsulates a change in the PulseAudio's connection context. + * + * When this event is fired, something has happened to the connection of this + * program to the PulseAudio server. + * + */ +class ContextEvent { + + /** + * Basically, what is the new state of the context + * + */ public static enum Type { UNCONNECTED, CONNECTING, AUTHORIZING, SETTING_NAME, READY, FAILED, TERMINATED }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/ContextListener.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,8 +37,14 @@ package org.classpath.icedtea.pulseaudio; -public interface ContextListener { +/** + * This interface specifies a listener for a change in PulseAudio's context state + * eg: the connection to the server becomes ready, fails or ends. + * + */ - public void update(ContextEvent e); +interface ContextListener { + + void update(ContextEvent e); }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Debug.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,15 +37,25 @@ package org.classpath.icedtea.pulseaudio; -public class Debug { +/** + * + * A simple debugging class. Set the debugging level through the system property + * pulseaudio.debugLevel=<Level>. Level is one of Verbose, Debug, Info, Warning, + * Error or None + * + * and then do DebugLevel.println(level, string) and so on + * + */ - public enum DebugLevel { +class Debug { + + enum DebugLevel { Verbose, Debug, Info, Warning, Error, None } private static DebugLevel currentDebugLevel = DebugLevel.None; - public static void initialize() { + static { // System.out.println("PulseAudio: initializing Debug"); String systemSetting; @@ -70,11 +80,11 @@ println(DebugLevel.Info, "Using debug level: " + currentDebugLevel); } - public static void println(String string) { + static void println(String string) { println(DebugLevel.Info, string); } - public static void print(DebugLevel level, String string) { + static void print(DebugLevel level, String string) { int result = level.compareTo(currentDebugLevel); if (result >= 0) { if (level.compareTo(DebugLevel.Error) >= 0) { @@ -87,7 +97,7 @@ } } - public static void println(DebugLevel level, String string) { + static void println(DebugLevel level, String string) { int result = level.compareTo(currentDebugLevel); if (result >= 0) {
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/EventLoop.java Wed Dec 03 10:07:38 2008 -0500 @@ -39,38 +39,40 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Semaphore; import org.classpath.icedtea.pulseaudio.ContextEvent.Type; import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; -/* - * any methods that can obstruct the behaviour of pa_mainloop should run - * synchronized +/** + * This class wraps pulseaudio's event loop. It also holds the lock used in the + * rest of pulse-java * * */ -public class EventLoop implements Runnable { +final class EventLoop implements Runnable { + + /* + * any methods that can obstruct the behaviour of pa_mainloop should run + * synchronized + */ /* * the threadLock object is the object used for synchronizing the * non-thread-safe operations of pulseaudio's c api */ - public Object threadLock = new Object(); + final Object threadLock = new Object(); private static EventLoop instance = null; private List<ContextListener> contextListeners; // private List<SourceDataLine> lines; - private String name; + private String appName; private String serverString; private int status; // private boolean eventLoopIsRunning = false; - public Semaphore finished = new Semaphore(0); - private List<String> targetPortNameList = new ArrayList<String>(); private List<String> sourcePortNameList = new ArrayList<String>(); @@ -105,27 +107,26 @@ private EventLoop() { contextListeners = new ArrayList<ContextListener>(); - threadLock = new Object(); } - synchronized public static EventLoop getEventLoop() { + synchronized static EventLoop getEventLoop() { if (instance == null) { instance = new EventLoop(); } return instance; } - public void setAppName(String name) { - this.name = name; + void setAppName(String appName) { + this.appName = appName; } - public void setServer(String serverString) { + void setServer(String serverString) { this.serverString = serverString; } @Override public void run() { - native_setup(this.name, this.serverString); + native_setup(this.appName, this.serverString); Debug.println(DebugLevel.Info, "Eventloop.run(): eventloop starting"); @@ -158,23 +159,23 @@ } - public void addContextListener(ContextListener contextListener) { + void addContextListener(ContextListener contextListener) { synchronized (contextListeners) { contextListeners.add(contextListener); } } - public void removeContextListener(ContextListener contextListener) { + void removeContextListener(ContextListener contextListener) { synchronized (contextListeners) { contextListeners.remove(contextListener); } } - public int getStatus() { + int getStatus() { return this.status; } - public void update(int status) { + void update(int status) { synchronized (threadLock) { // System.out.println(this.getClass().getName() // + ".update() called! status = " + status); @@ -187,8 +188,10 @@ fireEvent(new ContextEvent(Type.CONNECTING)); break; case 2: + // no op break; case 3: + // no op break; case 4: fireEvent(new ContextEvent(Type.READY)); @@ -220,17 +223,17 @@ } - public void setVolume(byte[] streamPointer, int volume) { + void setVolume(byte[] streamPointer, int volume) { synchronized (threadLock) { native_set_sink_volume(streamPointer, volume); } } - public byte[] getContextPointer() { + byte[] getContextPointer() { return contextPointer; } - public byte[] getMainLoopPointer() { + byte[] getMainLoopPointer() { return mainloopPointer; } @@ -238,7 +241,7 @@ private native byte[] nativeUpdateSourcePortNameList(); - protected synchronized List<String> updateTargetPortNameList() { + synchronized List<String> updateTargetPortNameList() { targetPortNameList = new ArrayList<String>(); Operation op; synchronized (this.threadLock) {
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Operation.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,21 +37,25 @@ package org.classpath.icedtea.pulseaudio; - -/* +/** * Encapsulates a pa_operation object * + * This is really needed only so that we can deallocate the reference counted + * object. Any time a function returns an Operation object, the reference has + * been incremented. The object wont be freed unless a releaseReference() is + * done. * - * This is really needed only so that we can deallocate the reference counted + * Please see the pulseaudio api docs for more information on a pa_opreation * object * * + * */ -public class Operation { +class Operation { - byte[] operationPointer; - EventLoop eventLoop; + private byte[] operationPointer; + private EventLoop eventLoop; public enum State { Running, Done, Cancelled, @@ -67,7 +71,7 @@ private native int native_get_state(); - public Operation(byte[] operationPointer) { + Operation(byte[] operationPointer) { assert (operationPointer != null); this.operationPointer = operationPointer; this.eventLoop = EventLoop.getEventLoop(); @@ -80,14 +84,20 @@ super.finalize(); } - public void addReference() { + /** + * Increase reference count by 1 + */ + void addReference() { assert (operationPointer != null); synchronized (eventLoop.threadLock) { native_ref(); } } - public void releaseReference() { + /** + * Decrease reference count by 1. If the count reaches 0, object will be freed + */ + void releaseReference() { assert (operationPointer != null); synchronized (eventLoop.threadLock) { native_unref(); @@ -95,14 +105,15 @@ operationPointer = null; } - public boolean isNull() { + // FIXME broken function + boolean isNull() { if (operationPointer == null) { return true; } return false; } - public State getState() { + State getState() { assert (operationPointer != null); int state; synchronized (eventLoop.threadLock) { @@ -121,7 +132,11 @@ } - public void waitForCompletion() { + /** + * Block until the operation has completed + * + */ + void waitForCompletion() { assert (operationPointer != null); boolean interrupted = false;
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Wed Dec 03 10:07:38 2008 -0500 @@ -44,12 +44,13 @@ import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; import javax.sound.sampled.LineUnavailableException; import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; import org.classpath.icedtea.pulseaudio.Stream.WriteListener; -public class PulseAudioClip extends PulseAudioDataLine implements Clip, +public final class PulseAudioClip extends PulseAudioDataLine implements Clip, PulseAudioPlaybackLine { private byte[] data = null; @@ -69,14 +70,18 @@ // the ending frame of the loop private int endFrame = 0; - public static final String DEFAULT_CLIP_NAME = "Clip"; + public static final String DEFAULT_CLIP_NAME = "Audio Clip"; private Object clipLock = new Object(); private int loopsLeft = 0; // private Semaphore clipSemaphore = new Semaphore(1); - private class ClipThread extends Thread { + /** + * This thread runs + * + */ + private final class ClipThread extends Thread { @Override public void run() { @@ -197,16 +202,18 @@ stream.removeWriteListener(writeListener); } - public PulseAudioClip(AudioFormat[] formats, AudioFormat defaultFormat) { - supportedFormats = formats; + PulseAudioClip(AudioFormat[] formats, AudioFormat defaultFormat) { + this.supportedFormats = formats; this.defaultFormat = defaultFormat; this.currentFormat = defaultFormat; this.volume = PulseAudioVolumeControl.MAX_VOLUME; + this.streamName = DEFAULT_CLIP_NAME; clipThread = new ClipThread(); } + @Override protected void connectLine(int bufferSize, Stream masterStream) throws LineUnavailableException { StreamBufferAttributes bufferAttributes = new StreamBufferAttributes( @@ -263,9 +270,6 @@ * * drain() on a Clip should block until the entire clip has finished playing * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4732218 - * - * - * @see org.classpath.icedtea.pulseaudio.PulseAudioDataLine#drain() */ @Override public void drain() { @@ -427,22 +431,28 @@ } + // FIXME + @Override public byte[] native_setVolume(float value) { return stream.native_setVolume(value); } + @Override public boolean isMuted() { return muted; } + @Override public void setMuted(boolean value) { muted = value; } + @Override public float getVolume() { return this.volume; } + @Override public void setVolume(float value) { this.volume = value; @@ -546,6 +556,7 @@ } + @Override public void stop() { if (!isOpen) { throw new IllegalStateException("Line not open"); @@ -571,7 +582,8 @@ } - public javax.sound.sampled.Line.Info getLineInfo() { + @Override + public Line.Info getLineInfo() { return new DataLine.Info(Clip.class, supportedFormats, StreamBufferAttributes.MIN_VALUE, StreamBufferAttributes.MAX_VALUE);
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Wed Dec 03 10:07:38 2008 -0500 @@ -47,13 +47,18 @@ import org.classpath.icedtea.pulseaudio.Stream.WriteListener; -public abstract class PulseAudioDataLine extends PulseAudioLine implements - DataLine { +/** + * + * This class contains code that is used by Clip, SourceDataLine and + * TargetDataLine + * + */ +abstract class PulseAudioDataLine extends PulseAudioLine implements DataLine { protected static final int DEFAULT_BUFFER_SIZE = StreamBufferAttributes.SANE_DEFAULT; - protected static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; - protected String streamName = "Java Stream"; + // override this to set the stream name + protected String streamName; // true between start() and stop() protected boolean isStarted = false; @@ -112,8 +117,6 @@ * values. SAME sample rate: _not_ safe because myFormat uses * AudioSystem.NOT_SPECIFIED. SAME frame rate: safe because we * _ignore_ it completely ;) - * - * */ float sampleRate = format.getSampleRate(); @@ -122,10 +125,12 @@ sampleRate = 44100.0f; } + String formatString = (String) myFormat + .getProperty(PulseAudioMixer.PULSEAUDIO_FORMAT_KEY); synchronized (eventLoop.threadLock) { + stream = new Stream(eventLoop.getContextPointer(), - streamName, Stream.Format.valueOf((String) myFormat - .getProperty(PULSEAUDIO_FORMAT_KEY)), + streamName, Stream.Format.valueOf(formatString), (int) sampleRate, myFormat.getChannels()); } @@ -142,6 +147,10 @@ } + /** + * This method adds the listeners used to find out when the stream has + * connected/disconnected etc to the actual stream. + */ private void addStreamListeners() { Stream.StateListener openCloseListener = new Stream.StateListener() { @@ -159,7 +168,6 @@ * line.close(); line.removeLineListener(listener) * * the listener is guaranteed to have run - * */ if (stream.getState() == Stream.State.READY) { @@ -282,11 +290,13 @@ } + @Override public void open() throws LineUnavailableException { assert (defaultFormat != null); open(defaultFormat, DEFAULT_BUFFER_SIZE); } + @Override public void close() { if (!isOpen) { @@ -313,7 +323,7 @@ isStarted = false; } - public void reconnectforSynchronization(Stream masterStream) + void reconnectforSynchronization(Stream masterStream) throws LineUnavailableException { sendEvents = false; drain(); @@ -334,6 +344,7 @@ sendEvents = true; } + @Override public void start() { if (!isOpen) { throw new IllegalStateException( @@ -363,6 +374,7 @@ } + @Override public synchronized void stop() { if (!isOpen) { throw new IllegalStateException( @@ -406,14 +418,13 @@ * * HOWEVER, the javadocs say the opposite thing! (need help from the jck = * official spec) - * - * */ - + @Override public boolean isActive() { return isStarted; } + @Override public boolean isRunning() { return isStarted && dataWritten; } @@ -421,8 +432,6 @@ protected abstract void connectLine(int bufferSize, Stream masterStream) throws LineUnavailableException; - public abstract void drain(); - public Stream getStream() { if (!isOpen) { throw new IllegalStateException("Line must be open"); @@ -447,10 +456,16 @@ return currentFormat; } + @Override public float getLevel() { return AudioSystem.NOT_SPECIFIED; } + /** + * + * @param streamName + * the name of this audio stream + */ public void setName(String streamName) { if (isOpen) { @@ -467,6 +482,10 @@ } + /** + * + * @return the name of this audio stream/clip + */ public String getName() { return streamName; }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioLine.java Wed Dec 03 10:07:38 2008 -0500 @@ -55,6 +55,7 @@ // resources protected boolean isOpen = false; + @Override public void addLineListener(LineListener listener) { this.lineListeners.add(listener); } @@ -98,6 +99,7 @@ return (Control[]) controls.toArray(new Control[0]); } + @Override public boolean isControlSupported(Type control) { for (Control myControl : controls) { if (myControl.getType().getClass() == control.getClass()) { @@ -107,10 +109,12 @@ return false; } + @Override public boolean isOpen() { return isOpen; } + @Override public void removeLineListener(LineListener listener) { lineListeners.remove(listener); }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,8 +37,6 @@ package org.classpath.icedtea.pulseaudio; -import java.io.File; -import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; @@ -49,7 +47,6 @@ import java.util.concurrent.Semaphore; import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioPermission; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; @@ -63,17 +60,15 @@ import javax.sound.sampled.Port; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.TargetDataLine; -import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.AudioFormat.Encoding; import javax.sound.sampled.Control.Type; import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; -public class PulseAudioMixer implements javax.sound.sampled.Mixer { +public final class PulseAudioMixer implements Mixer { // singleton - public EventLoop eventLoop; - public Thread eventLoopThread; + private Thread eventLoopThread; private List<Line.Info> sourceLineInfos = new ArrayList<Line.Info>(); private List<Line.Info> staticSourceLineInfos = new ArrayList<Line.Info>(); @@ -83,8 +78,8 @@ private static PulseAudioMixer _instance = null; - private static final String DEFAULT_APP_NAME = "Java App"; - private static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; + private static final String DEFAULT_APP_NAME = "Java"; + static final String PULSEAUDIO_FORMAT_KEY = "PulseAudioFormatKey"; private boolean isOpen = false; @@ -326,6 +321,10 @@ if (Port.Info.class.isInstance(info)) { Port.Info portInfo = (Port.Info) info; if (portInfo.isSource()) { + /* check for permission to record audio */ + AudioPermission perm = new AudioPermission("record", null); + perm.checkGuard(null); + return new PulseAudioSourcePort(portInfo.getName()); } else { return new PulseAudioTargetPort(portInfo.getName()); @@ -357,13 +356,12 @@ return PulseAudioMixerInfo.getInfo(); } - public javax.sound.sampled.Line.Info[] getSourceLineInfo() { + public Line.Info[] getSourceLineInfo() { return sourceLineInfos.toArray(new Line.Info[0]); } @Override - public javax.sound.sampled.Line.Info[] getSourceLineInfo( - javax.sound.sampled.Line.Info info) { + public Line.Info[] getSourceLineInfo(Line.Info info) { ArrayList<Line.Info> infos = new ArrayList<Line.Info>(); for (Line.Info supportedInfo : sourceLineInfos) { @@ -371,31 +369,30 @@ infos.add(supportedInfo); } } - return infos.toArray(new Line.Info[infos.size()]); + return infos.toArray(new Line.Info[0]); } @Override public Line[] getSourceLines() { - return (Line[]) sourceLines.toArray(new Line[0]); + return sourceLines.toArray(new Line[0]); } @Override - public javax.sound.sampled.Line.Info[] getTargetLineInfo() { + public Line.Info[] getTargetLineInfo() { return targetLineInfos.toArray(new Line.Info[0]); } @Override - public javax.sound.sampled.Line.Info[] getTargetLineInfo( - javax.sound.sampled.Line.Info info) { - ArrayList<javax.sound.sampled.Line.Info> infos = new ArrayList<javax.sound.sampled.Line.Info>(); + public Line.Info[] getTargetLineInfo(Line.Info info) { + ArrayList<Line.Info> infos = new ArrayList<Line.Info>(); for (Line.Info supportedInfo : targetLineInfos) { if (info.matches(supportedInfo)) { infos.add(supportedInfo); } } - return infos.toArray(new Line.Info[infos.size()]); + return infos.toArray(new Line.Info[0]); } @Override @@ -409,7 +406,7 @@ } @Override - public boolean isLineSupported(javax.sound.sampled.Line.Info info) { + public boolean isLineSupported(Line.Info info) { if (info != null) { for (Line.Info myInfo : sourceLineInfos) { if (info.matches(myInfo)) { @@ -583,50 +580,80 @@ } - public void open(String appName, String host) throws UnknownHostException, - LineUnavailableException { - openRemote(appName, host); - } - public void openLocal() throws LineUnavailableException { openLocal(DEFAULT_APP_NAME); } public void openLocal(String appName) throws LineUnavailableException { - try { - openRemote(appName, null); - } catch (UnknownHostException e) { - // not possible - } + openImpl(appName, null); } public void openRemote(String appName, String host) throws UnknownHostException, LineUnavailableException { - openRemote(appName, host, null); + if (host == null) { + throw new NullPointerException("hostname"); + } + + final int PULSEAUDIO_DEFAULT_PORT = 4713; + + /* + * If trying to connect to a remote machine, check for permissions + */ + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkConnect(host,PULSEAUDIO_DEFAULT_PORT ); + } + + openImpl(appName, host); } - synchronized public void openRemote(String appName, String host, - Integer port) throws UnknownHostException, LineUnavailableException { + public void openRemote(String appName, String host, int port) + throws UnknownHostException, LineUnavailableException { + + if ((port < 1) && (port != -1)) { + throw new IllegalArgumentException("Invalid value for port"); + } + + if (host == null) { + throw new NullPointerException("hostname"); + } /* - * only allow the mixer to be controlled if either playback or recording - * is allowed + * If trying to connect to a remote machine, check for permissions */ + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkConnect(host, port); + } + + InetAddress addr = InetAddress.getAllByName(host)[0]; + + host = addr.getHostAddress(); + host = host + ":" + String.valueOf(port); + + openImpl(appName, host); + + } + + /* + * + * @param appName name of the application + * + * @param hostAndIp a string consisting of the host and ip address of the + * server to connect to. Format: "<host>:<ip>". Set to null to indicate a + * local connection + */ + synchronized private void openImpl(String appName, String hostAndIp) + throws LineUnavailableException { if (isOpen) { throw new IllegalStateException("Mixer is already open"); } - InetAddress addr = InetAddress.getAllByName(host)[0]; - - if (port != null) { - host = addr.getHostAddress(); - host = host + ":" + String.valueOf(port); - } - + EventLoop eventLoop; eventLoop = EventLoop.getEventLoop(); eventLoop.setAppName(appName); - eventLoop.setServer(host); + eventLoop.setServer(hostAndIp); ContextListener generalEventListener = new ContextListener() { @Override @@ -736,120 +763,6 @@ } } - public static void debug(String string) { - System.out.println("DEBUG: " + string); - } - - public static void main(String[] args) throws Exception { - Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); - Mixer.Info selectedMixerInfo = null; - // int i = 0; - for (Mixer.Info info : mixerInfos) { - // System.out.println("Mixer Line " + i++ + ": " + info.getName() + - // " " + info.getDescription()); - if (info.getName().contains("PulseAudio")) { - selectedMixerInfo = info; - System.out.println(selectedMixerInfo); - } - } - - PulseAudioMixer mixer = (PulseAudioMixer) AudioSystem - .getMixer(selectedMixerInfo); - - mixer.open(); - - String fileName1 = "testsounds/startup.wav"; - PulseAudioSourceDataLine line1; - line1 = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - line1.setName("Line 1"); - - String fileName2 = "testsounds/logout.wav"; - PulseAudioSourceDataLine line2; - line2 = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info( - SourceDataLine.class)); - line2.setName("Line 2"); - - ThreadWriter writer1 = mixer.new ThreadWriter(line1, fileName1); - ThreadWriter writer2 = mixer.new ThreadWriter(line2, fileName2); - // line2.start(); - // line1.start(); - - Line[] lines = { line1, line2 }; - mixer.synchronize(lines, true); - - // line2.stop(); - - debug("PulseAudioMixer: " + line1.getName() + " and " + line2.getName() - + " synchronized"); - writer1.start(); - writer2.start(); - - debug("PulseAudioMixer: writers started"); - line2.start(); - // line1.stop(); - // line1.start(); - debug("PulseAudioMixer: Started a line"); - - writer1.join(); - writer2.join(); - - debug("PulseAudioMixer: both lines joined"); - - line2.close(); - debug("PulseAudioMixer: " + line2.getName() + " closed"); - - line1.close(); - debug("PulseAudioMixer: " + line1.getName() + " closed"); - - mixer.close(); - debug("PulseAudioMixer: mixer closed"); - - } - - public class ThreadWriter extends Thread { - - private PulseAudioSourceDataLine line; - private AudioInputStream audioInputStream; - - public ThreadWriter(PulseAudioSourceDataLine line, String fileName) - throws UnsupportedAudioFileException, IOException, - LineUnavailableException { - this.line = line; - File soundFile1 = new File(fileName); - audioInputStream = AudioSystem.getAudioInputStream(soundFile1); - AudioFormat audioFormat = audioInputStream.getFormat(); - line.open(audioFormat); - } - - @Override - public void run() { - debug("PulseAudioMixer: ThreadWriter: run(): entering"); - - // line.start(); - // debug("PulseAudioMixer: " + line.getName() + " started"); - - byte[] abData = new byte[1000]; - int bytesRead = 0; - try { - while (bytesRead >= 0) { - bytesRead = audioInputStream.read(abData, 0, abData.length); - if (bytesRead > 0) { - line.write(abData, 0, bytesRead); - // debug("PulseAudioMixer: wrote " + bytesRead + "data - // on " - // + line.getName()); - } - } - } catch (IOException e) { - debug("PulseAudioMixer: ThreadWriter: run(): exception doing a read()"); - } - - debug("PulseAudioMixer: ThreadWriter: run(): leaving"); - - } - } - void addSourceLine(PulseAudioLine line) { sourceLines.add(line); }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerInfo.java Wed Dec 03 10:07:38 2008 -0500 @@ -39,7 +39,7 @@ import javax.sound.sampled.Mixer; -public class PulseAudioMixerInfo extends Mixer.Info { +public final class PulseAudioMixerInfo extends Mixer.Info { // singleton private static PulseAudioMixerInfo _instance = null; @@ -52,8 +52,8 @@ // the "getInstance()" method synchronized public static PulseAudioMixerInfo getInfo() { if (_instance == null) { - _instance = new PulseAudioMixerInfo("PulseAudio Mixer", "icedtea", - "the ear-candy mixer", "0.01"); + _instance = new PulseAudioMixerInfo("PulseAudio Mixer", "IcedTea", + "the ear-candy mixer", "0.02"); } return _instance;
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMixerProvider.java Wed Dec 03 10:07:38 2008 -0500 @@ -43,10 +43,6 @@ public class PulseAudioMixerProvider extends javax.sound.sampled.spi.MixerProvider { - public PulseAudioMixerProvider() { - Debug.initialize(); - } - @Override public Mixer getMixer(Info info) { // System.out.println("DEBUG: getMixer called");
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMuteControl.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioMuteControl.java Wed Dec 03 10:07:38 2008 -0500 @@ -39,40 +39,35 @@ import javax.sound.sampled.BooleanControl; -class PulseAudioMuteControl extends BooleanControl { - +final class PulseAudioMuteControl extends BooleanControl { + private PulseAudioVolumeControl volumeControl; private PulseAudioPlaybackLine line; - protected PulseAudioMuteControl(PulseAudioPlaybackLine line, PulseAudioVolumeControl volumeControl) { + protected PulseAudioMuteControl(PulseAudioPlaybackLine line, + PulseAudioVolumeControl volumeControl) { super(BooleanControl.Type.MUTE, false, "Volume muted", "Volume on"); this.volumeControl = volumeControl; this.line = line; } - - - - - public synchronized void setValue(boolean value) { - if(!line.isOpen()) { - return; - } - - if (value == true) { - line.setMuted(true); - volumeControl.setStreamVolume(0); - } else { - line.setMuted(false); - float newValue = volumeControl.getValue(); - volumeControl.setStreamVolume(newValue); - } + public synchronized void setValue(boolean value) { + if (!line.isOpen()) { + return; } - public synchronized boolean getValue() { - return line.isMuted(); + if (value == true) { + line.setMuted(true); + volumeControl.setStreamVolume(0); + } else { + line.setMuted(false); + float newValue = volumeControl.getValue(); + volumeControl.setStreamVolume(newValue); } - } + public synchronized boolean getValue() { + return line.isMuted(); + } +}
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioPort.java Wed Dec 03 10:07:38 2008 -0500 @@ -38,10 +38,11 @@ package org.classpath.icedtea.pulseaudio; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Line; import javax.sound.sampled.LineEvent; import javax.sound.sampled.Port; -public abstract class PulseAudioPort extends PulseAudioLine implements Port, +abstract class PulseAudioPort extends PulseAudioLine implements Port, PulseAudioPlaybackLine { private String name; @@ -66,8 +67,8 @@ SecurityWrapper.loadNativeLibrary(); } - public PulseAudioPort(String name) { - this.name = name; + PulseAudioPort(String portName) { + this.name = portName; this.eventLoop = EventLoop.getEventLoop(); this.contextPointer = eventLoop.getContextPointer(); @@ -89,29 +90,38 @@ // System.out.println("Opened Target Port " + name); } + + // FIXME why public + @Override public abstract byte[] native_setVolume(float newValue); + // FIXME why public public abstract byte[] native_updateVolumeInfo(); + @Override public boolean isMuted() { return muted; } + @Override public void setMuted(boolean value) { muted = value; } + @Override public float getVolume() { // FIXME need to query system for volume return this.volume; } + @Override public void setVolume(float value) { this.volume = value; } + // FIXME public synchronized void updateVolumeInfo() { Operation op; synchronized (eventLoop.threadLock) { @@ -122,6 +132,7 @@ op.releaseReference(); } + // FIXME public void update_channels_and_volume(int channels, float volume) { this.channels = channels; this.volume = volume; @@ -137,7 +148,7 @@ } @Override - public abstract javax.sound.sampled.Line.Info getLineInfo(); + public abstract Line.Info getLineInfo(); @Override public void open() {
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Wed Dec 03 10:07:38 2008 -0500 @@ -41,28 +41,35 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; import javax.sound.sampled.LineListener; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; -public class PulseAudioSourceDataLine extends PulseAudioDataLine implements - SourceDataLine, PulseAudioPlaybackLine { +public final class PulseAudioSourceDataLine extends PulseAudioDataLine + implements SourceDataLine, PulseAudioPlaybackLine { private PulseAudioMuteControl muteControl; private PulseAudioVolumeControl volumeControl; private boolean muted; private float volume; - public PulseAudioSourceDataLine(AudioFormat[] formats, - AudioFormat defaultFormat) { + public static final String DEFAULT_SOURCEDATALINE_NAME = "Audio Stream"; + + /* + * Package-private constructor only called by PulseAudioMixer + */ + PulseAudioSourceDataLine(AudioFormat[] formats, AudioFormat defaultFormat) { this.supportedFormats = formats; this.lineListeners = new ArrayList<LineListener>(); this.defaultFormat = defaultFormat; this.currentFormat = defaultFormat; this.volume = PulseAudioVolumeControl.MAX_VOLUME; + this.streamName = DEFAULT_SOURCEDATALINE_NAME; + } @Override @@ -89,29 +96,36 @@ open(format, DEFAULT_BUFFER_SIZE); } + // FIXME public byte[] native_setVolume(float value) { synchronized (eventLoop.threadLock) { return stream.native_setVolume(value); } } + // FIXME + @Override public boolean isMuted() { return muted; } + @Override public void setMuted(boolean value) { muted = value; } + @Override public float getVolume() { return this.volume; } + @Override synchronized public void setVolume(float value) { this.volume = value; } + @Override protected void connectLine(int bufferSize, Stream masterStream) throws LineUnavailableException { StreamBufferAttributes bufferAttributes = new StreamBufferAttributes( @@ -203,8 +217,7 @@ } // only write entire frames, so round down avialableSize to - // a - // multiple of frameSize + // a multiple of frameSize availableSize = (availableSize / frameSize) * frameSize; synchronized (this) { @@ -234,20 +247,24 @@ return sizeWritten; } + @Override public int available() { synchronized (eventLoop.threadLock) { return stream.getWritableSize(); } }; + @Override public int getFramePosition() { return (int) framesSinceOpen; } + @Override public long getLongFramePosition() { return framesSinceOpen; } + @Override public long getMicrosecondPosition() { float frameRate = currentFormat.getFrameRate(); @@ -337,7 +354,8 @@ } - public javax.sound.sampled.Line.Info getLineInfo() { + @Override + public Line.Info getLineInfo() { return new DataLine.Info(SourceDataLine.class, supportedFormats, StreamBufferAttributes.MIN_VALUE, StreamBufferAttributes.MAX_VALUE);
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourcePort.java Wed Dec 03 10:07:38 2008 -0500 @@ -38,9 +38,10 @@ package org.classpath.icedtea.pulseaudio; import javax.sound.sampled.AudioPermission; +import javax.sound.sampled.Line; import javax.sound.sampled.Port; -public class PulseAudioSourcePort extends PulseAudioPort { +final class PulseAudioSourcePort extends PulseAudioPort { /* aka mic */ @@ -48,7 +49,7 @@ SecurityWrapper.loadNativeLibrary(); } - public PulseAudioSourcePort(String name) { + PulseAudioSourcePort(String name) { super(name); } @@ -80,12 +81,14 @@ super.close(); } + // FIXME public native byte[] native_setVolume(float newValue); + // FIXME public synchronized native byte[] native_updateVolumeInfo(); @Override - public javax.sound.sampled.Line.Info getLineInfo() { + public Line.Info getLineInfo() { return new Port.Info(Port.class, getName(), false); }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Wed Dec 03 10:07:38 2008 -0500 @@ -38,36 +38,39 @@ package org.classpath.icedtea.pulseaudio; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioPermission; import javax.sound.sampled.DataLine; -import javax.sound.sampled.AudioPermission; +import javax.sound.sampled.Line; import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.TargetDataLine; import org.classpath.icedtea.pulseaudio.Debug.DebugLevel; -public class PulseAudioTargetDataLine extends PulseAudioDataLine implements - TargetDataLine { +public final class PulseAudioTargetDataLine extends PulseAudioDataLine + implements TargetDataLine { /* * This contains the data from the PulseAudio buffer that has since been * dropped. If 20 bytes of a fragment of size 200 are read, the other 180 * are dumped in this */ - byte[] fragmentBuffer; + private byte[] fragmentBuffer; /* * these are set to true only by the respective functions (flush(), drain()) * set to false only by read() */ - boolean flushed = false; - boolean drained = false; + private boolean flushed = false; + private boolean drained = false; - public PulseAudioTargetDataLine(AudioFormat[] formats, - AudioFormat defaultFormat) { - supportedFormats = formats; + public static final String DEFAULT_TARGETDATALINE_NAME = "Audio Stream"; + + PulseAudioTargetDataLine(AudioFormat[] formats, AudioFormat defaultFormat) { + this.supportedFormats = formats; this.defaultFormat = defaultFormat; this.currentFormat = defaultFormat; + this.streamName = DEFAULT_TARGETDATALINE_NAME; } @@ -123,6 +126,7 @@ open(format, DEFAULT_BUFFER_SIZE); } + @Override protected void connectLine(int bufferSize, Stream masterStream) throws LineUnavailableException { int fragmentSize = bufferSize / 10 > 500 ? bufferSize / 10 : 500; @@ -238,9 +242,9 @@ stream.drop(); if (currentFragment == null) { - // System.out - // .println("DEBUG: PulseAudioTargetDataLine:read(): - // error in stream.peek()"); + Debug.println(DebugLevel.Verbose, + "PulseAudioTargetDataLine.read(): " + + " error in stream.peek()"); continue; } @@ -330,6 +334,7 @@ } + @Override public int available() { if (!isOpen) { throw new IllegalStateException("Line must be open"); @@ -340,14 +345,17 @@ } } + @Override public int getFramePosition() { return (int) framesSinceOpen; } + @Override public long getLongFramePosition() { return framesSinceOpen; } + @Override public long getMicrosecondPosition() { return (long) (framesSinceOpen / currentFormat.getFrameRate()); } @@ -372,7 +380,8 @@ fireLineEvent(new LineEvent(this, LineEvent.Type.STOP, framesSinceOpen)); } - public javax.sound.sampled.Line.Info getLineInfo() { + @Override + public Line.Info getLineInfo() { return new DataLine.Info(TargetDataLine.class, supportedFormats, StreamBufferAttributes.MIN_VALUE, StreamBufferAttributes.MAX_VALUE);
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetPort.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,9 +37,10 @@ package org.classpath.icedtea.pulseaudio; +import javax.sound.sampled.Line; import javax.sound.sampled.Port; -public class PulseAudioTargetPort extends PulseAudioPort { +final class PulseAudioTargetPort extends PulseAudioPort { /* aka speaker */ @@ -47,11 +48,12 @@ SecurityWrapper.loadNativeLibrary(); } - public PulseAudioTargetPort(String name) { + PulseAudioTargetPort(String name) { super(name); } + @Override public void open() { super.open(); @@ -60,6 +62,7 @@ parent.addTargetLine(this); } + @Override public void close() { if (!isOpen) { @@ -72,12 +75,15 @@ super.close(); } + + // FIXME public native byte[] native_setVolume(float newValue); + // FIXME public synchronized native byte[] native_updateVolumeInfo(); @Override - public javax.sound.sampled.Line.Info getLineInfo() { + public Line.Info getLineInfo() { return new Port.Info(Port.class, getName(), false); }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/PulseAudioVolumeControl.java Wed Dec 03 10:07:38 2008 -0500 @@ -39,10 +39,10 @@ import javax.sound.sampled.FloatControl; -class PulseAudioVolumeControl extends FloatControl { +final class PulseAudioVolumeControl extends FloatControl { - public static final int MAX_VOLUME = 65536; - public static final int MIN_VOLUME = 0; + static final int MAX_VOLUME = 65536; + static final int MIN_VOLUME = 0; protected PulseAudioVolumeControl(PulseAudioPlaybackLine line, EventLoop eventLoop) { @@ -56,6 +56,7 @@ private EventLoop eventLoop; private PulseAudioPlaybackLine line; + @Override public synchronized void setValue(float newValue) { if (newValue > MAX_VOLUME || newValue < MIN_VOLUME) { throw new IllegalArgumentException("invalid value");
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/SecurityWrapper.java Wed Dec 03 10:07:38 2008 -0500 @@ -3,9 +3,13 @@ import java.security.AccessController; import java.security.PrivilegedAction; -class SecurityWrapper { +/** + * A wrapper around the security sensitive functions + * + */ +final class SecurityWrapper { - public static void loadNativeLibrary() { + static void loadNativeLibrary() { if (System.getSecurityManager() != null) { PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/Stream.java Wed Dec 03 10:07:38 2008 -0500 @@ -47,8 +47,12 @@ * This class encapsulates a pa_stream object and provides easier access to the * native functions * + * + * for more details on this see the pa_stream_* functions in the pulseaudio api + * docs + * */ -public class Stream { +final class Stream { public interface StateListener { public void update(); @@ -172,9 +176,9 @@ public native int bytesInBuffer(); /* - * pa_operation pa_stream_update_timing_info (pa_stream *p, - * pa_stream_success_cb_t cb, void *userdata) Request a timing info - * structure update for a stream. + * pa_operation pa_stream_update_timing_info (pa_streamp, + * pa_stream_success_cb_t cb, voiduserdata) Request a timing info structure + * update for a stream. */ private native int native_pa_stream_is_corked(); @@ -184,8 +188,8 @@ private native byte[] native_pa_stream_flush(); /* - * pa_operation pa_stream_prebuf (pa_stream *s, pa_stream_success_cb_t cb, - * void *userdata) Reenable prebuffering as specified in the pa_buffer_attr + * pa_operation pa_stream_prebuf (pa_streams, pa_stream_success_cb_t cb, + * voiduserdata) Reenable prebuffering as specified in the pa_buffer_attr * structure. */ @@ -201,41 +205,41 @@ private native long native_pa_stream_get_latency(); /* - * const pa_timing_info * pa_stream_get_timing_info (pa_stream *s) Return - * the latest raw timing data structure. + * const pa_timing_info pa_stream_get_timing_info (pa_streams) Return the + * latest raw timing data structure. */ - native StreamSampleSpecification native_pa_stream_get_sample_spec(); + private native StreamSampleSpecification native_pa_stream_get_sample_spec(); /* - * const pa_channel_map * pa_stream_get_channel_map (pa_stream *s) Return a + * const pa_channel_map pa_stream_get_channel_map (pa_streams) Return a * pointer to the stream's channel map. const - * */ - native StreamBufferAttributes native_pa_stream_get_buffer_attr(); + private native StreamBufferAttributes native_pa_stream_get_buffer_attr(); - native byte[] native_pa_stream_set_buffer_attr(StreamBufferAttributes info); + private native byte[] native_pa_stream_set_buffer_attr( + StreamBufferAttributes info); private native byte[] native_pa_stream_update_sample_rate(int rate); - public native byte[] native_setVolume(float newValue); + native byte[] native_setVolume(float newValue); /* - * pa_operation pa_stream_proplist_update (pa_stream *s, pa_update_mode_t - * mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata) Update - * the property list of the sink input/source output of this stream, adding - * new entries. pa_operation * pa_stream_proplist_remove (pa_stream *s, - * const char *const keys[], pa_stream_success_cb_t cb, void *userdata) - * Update the property list of the sink input/source output of this stream, - * remove entries. int pa_stream_set_monitor_stream (pa_stream *s, uint32_t + * pa_operation pa_stream_proplist_update (pa_streams, pa_update_mode_t + * mode, pa_proplistp, pa_stream_success_cb_t cb, voiduserdata) Update the + * property list of the sink input/source output of this stream, adding new + * entries. pa_operation pa_stream_proplist_remove (pa_streams, const char + * const keys[], pa_stream_success_cb_t cb, voiduserdata) Update the + * property list of the sink input/source output of this stream, remove + * entries. int pa_stream_set_monitor_stream (pa_streams, uint32_t * sink_input_idx) For record streams connected to a monitor source: monitor * only a very specific sink input of the sink. uint32_t - * pa_stream_get_monitor_stream (pa_stream *s) Return what has been set with + * pa_stream_get_monitor_stream (pa_streams) Return what has been set with * pa_stream_set_monitor_stream() ebfore. */ - public Stream(byte[] contextPointer, String name, Format format, - int sampleRate, int channels) { + Stream(byte[] contextPointer, String name, Format format, int sampleRate, + int channels) { // System.out.println("format: " + format.toString()); stateListeners = new LinkedList<StateListener>(); @@ -257,129 +261,128 @@ spec.getRate(), spec.getChannels()); } - public void addStateListener(StateListener listener) { + void addStateListener(StateListener listener) { synchronized (stateListeners) { stateListeners.add(listener); } } - public void removeStateListener(StateListener listener) { + void removeStateListener(StateListener listener) { synchronized (stateListeners) { stateListeners.remove(listener); } } - public void addWriteListener(WriteListener listener) { + void addWriteListener(WriteListener listener) { synchronized (writeListeners) { writeListeners.add(listener); } } - public void removeWriteListener(WriteListener listener) { + void removeWriteListener(WriteListener listener) { synchronized (writeListeners) { writeListeners.remove(listener); } } - public void addReadListener(ReadListener listener) { + void addReadListener(ReadListener listener) { synchronized (readListeners) { readListeners.add(listener); } } - public void removeReadListener(ReadListener listener) { + void removeReadListener(ReadListener listener) { synchronized (readListeners) { readListeners.remove(listener); } } - public void addOverflowListener(OverflowListener listener) { + void addOverflowListener(OverflowListener listener) { synchronized (overflowListeners) { overflowListeners.add(listener); } } - public void removeOverflowListener(OverflowListener listener) { + void removeOverflowListener(OverflowListener listener) { synchronized (overflowListeners) { overflowListeners.remove(listener); } } - public void addUnderflowListener(UnderflowListener listener) { + void addUnderflowListener(UnderflowListener listener) { synchronized (underflowListeners) { underflowListeners.add(listener); } } - public void removeUnderflowListener(UnderflowListener listener) { + void removeUnderflowListener(UnderflowListener listener) { synchronized (underflowListeners) { underflowListeners.remove(listener); } } - public void addCorkListener(CorkListener listener) { + void addCorkListener(CorkListener listener) { synchronized (corkListeners) { corkListeners.add(listener); } } - public void removeCorkListener(CorkListener listener) { + void removeCorkListener(CorkListener listener) { synchronized (corkListeners) { corkListeners.remove(listener); } } - public void addPlaybackStartedListener(PlaybackStartedListener listener) { + void addPlaybackStartedListener(PlaybackStartedListener listener) { synchronized (playbackStartedListeners) { playbackStartedListeners.add(listener); } } - public void removePlaybackStartedListener(PlaybackStartedListener listener) { + void removePlaybackStartedListener(PlaybackStartedListener listener) { synchronized (playbackStartedListeners) { playbackStartedListeners.remove(listener); } } - public void addLatencyUpdateListener(LatencyUpdateListener listener) { + void addLatencyUpdateListener(LatencyUpdateListener listener) { synchronized (latencyUpdateListeners) { latencyUpdateListeners.add(listener); } } - public void removeLatencyUpdateListener(LatencyUpdateListener listener) { + void removeLatencyUpdateListener(LatencyUpdateListener listener) { synchronized (playbackStartedListeners) { latencyUpdateListeners.remove(listener); } } - public void addMovedListener(MovedListener listener) { + void addMovedListener(MovedListener listener) { synchronized (movedListeners) { movedListeners.add(listener); } } - public void removeMovedListener(MovedListener listener) { + void removeMovedListener(MovedListener listener) { synchronized (movedListeners) { movedListeners.remove(listener); } } - public void addSuspendedListener(SuspendedListener listener) { + void addSuspendedListener(SuspendedListener listener) { synchronized (suspendedListeners) { suspendedListeners.add(listener); } } - public void removeSuspendedListener(SuspendedListener listener) { + void removeSuspendedListener(SuspendedListener listener) { synchronized (suspendedListeners) { suspendedListeners.remove(listener); } } - - public Stream.State getState() { + Stream.State getState() { int state = native_pa_stream_get_state(); switch (state) { case 0: @@ -398,11 +401,11 @@ } - public byte[] getContextPointer() { + byte[] getContextPointer() { return native_pa_stream_get_context(); } - public int getSinkInputIndex() { + int getSinkInputIndex() { return native_pa_stream_get_index(); } @@ -411,7 +414,7 @@ * @return the index of the sink or source this stream is connected to in * the server */ - public int getDeviceIndex() { + int getDeviceIndex() { return native_pa_stream_get_device_index(); } @@ -420,7 +423,7 @@ * @return the name of the sink or source this stream is connected to in the * server */ - public String getDeviceName() { + String getDeviceName() { return native_pa_stream_get_device_name(); } @@ -429,7 +432,7 @@ * * @return */ - public boolean isSuspended() { + boolean isSuspended() { return (native_pa_stream_is_suspended() != 0); } @@ -441,7 +444,7 @@ * <code>null</code for the default device * @throws LineUnavailableException */ - public void connectForPlayback(String deviceName, + void connectForPlayback(String deviceName, StreamBufferAttributes bufferAttributes, byte[] syncStreamPointer) throws LineUnavailableException { @@ -462,7 +465,7 @@ * @throws LineUnavailableException * */ - public void connectForRecording(String deviceName, + void connectForRecording(String deviceName, StreamBufferAttributes bufferAttributes) throws LineUnavailableException { @@ -480,7 +483,7 @@ /** * Disconnect a stream from a source/sink. */ - public void disconnect() { + void disconnect() { int returnValue = native_pa_stream_disconnect(); assert (returnValue == 0); } @@ -492,7 +495,7 @@ * @param length * @return */ - public int write(byte[] data, int offset, int length) { + int write(byte[] data, int offset, int length) { return native_pa_stream_write(data, offset, length); } @@ -502,7 +505,7 @@ * * @param data */ - public byte[] peek() { + byte[] peek() { return native_pa_stream_peek(); } @@ -510,7 +513,7 @@ * * Remove the current fragment on record streams. */ - public void drop() { + void drop() { native_pa_stream_drop(); } @@ -519,7 +522,7 @@ * * @return */ - public int getWritableSize() { + int getWritableSize() { return native_pa_stream_writable_size(); } @@ -528,7 +531,7 @@ * * @return */ - public int getReableSize() { + int getReableSize() { return native_pa_stream_readable_size(); } @@ -537,12 +540,12 @@ * * @return */ - public Operation drain() { + Operation drain() { Operation drainOperation = new Operation(native_pa_stream_drain()); return drainOperation; } - public Operation updateTimingInfo() { + Operation updateTimingInfo() { Operation updateOperation = new Operation( native_pa_stream_updateTimingInfo()); return updateOperation; @@ -656,7 +659,7 @@ } } - public boolean isCorked() { + boolean isCorked() { int corked = native_pa_stream_is_corked(); if (corked < 0) { throw new IllegalStateException("Unable to determine state"); @@ -670,17 +673,17 @@ * @param cork * @return */ - public Operation cork(boolean cork) { + Operation cork(boolean cork) { int yes = cork ? 1 : 0; Operation corkOperation = new Operation(native_pa_stream_cork(yes)); return corkOperation; } - public Operation cork() { + Operation cork() { return cork(true); } - public Operation unCork() { + Operation unCork() { return cork(false); } @@ -689,14 +692,14 @@ * * @return */ - public Operation flush() { + Operation flush() { Operation flushOperation = new Operation(native_pa_stream_flush()); return flushOperation; } /* - * Operation pa_stream_prebuf (pa_stream *s, pa_stream_success_cb_t cb, void - * *userdata) + * Operation pa_stream_prebuf (pa_streams, pa_stream_success_cb_t cb, void + * userdata) * * Reenable prebuffering as specified in the pa_buffer_attr structure. */ @@ -704,7 +707,7 @@ /** * Request immediate start of playback on this stream. */ - public Operation triggerStart() { + Operation triggerStart() { Operation triggerOperation = new Operation(native_pa_stream_trigger()); return triggerOperation; } @@ -715,61 +718,62 @@ * @param name * @return */ - public Operation setName(String name) { + Operation setName(String name) { Operation setNameOperation = new Operation( native_pa_stream_set_name(name)); return setNameOperation; } - public long getTime() { + /** + * + * + * @return a time between ? and ? + */ + long getTime() { return native_pa_stream_get_time(); } /** - * @returns the total stream latency in microseconds + * @return the total stream latency in microseconds */ - public long getLatency() { + long getLatency() { return native_pa_stream_get_latency(); } /* - * const pa_timing_info * pa_stream_get_timing_info (pa_stream *s) Return - * the latest raw timing data structure. - * + * const pa_timing_info pa_stream_get_timing_info (pa_streams) Return the + * latest raw timing data structure. */ - public Format getFormat() { + Format getFormat() { return format; } /* - * const pa_channel_map * pa_stream_get_channel_map (pa_stream *s) Return a + * const pa_channel_map pa_stream_get_channel_map (pa_streams) Return a * pointer to the stream's channel map. */ - public StreamBufferAttributes getBufferAttributes() { + StreamBufferAttributes getBufferAttributes() { return native_pa_stream_get_buffer_attr(); } - public Operation setBufferAtrributes(StreamBufferAttributes attr) { + Operation setBufferAtrributes(StreamBufferAttributes attr) { return new Operation(native_pa_stream_set_buffer_attr(attr)); } /** * Change the stream sampling rate during playback. - * */ - Operation updateSampleRate(int rate) { return new Operation(native_pa_stream_update_sample_rate(rate)); - } - public byte[] getStreamPointer() { + byte[] getStreamPointer() { return streamPointer; } - public void free() { + void free() { native_pa_stream_unref(); }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamBufferAttributes.java Wed Dec 03 10:07:38 2008 -0500 @@ -37,7 +37,7 @@ package org.classpath.icedtea.pulseaudio; -public class StreamBufferAttributes { +class StreamBufferAttributes { public static final int SANE_DEFAULT = 50000; @@ -52,7 +52,7 @@ private int minimumRequest; private int fragmentSize; - public StreamBufferAttributes(int maxLength, int targetLength, + StreamBufferAttributes(int maxLength, int targetLength, int preBuffering, int minimumRequest, int fragmentSize) { this.maxLength = maxLength; this.targetLength = targetLength; @@ -61,23 +61,23 @@ this.fragmentSize = fragmentSize; } - public int getMaxLength() { + int getMaxLength() { return maxLength; } - public int getTargetLength() { + int getTargetLength() { return targetLength; } - public int getPreBuffering() { + int getPreBuffering() { return preBuffering; } - public int getMinimumRequest() { + int getMinimumRequest() { return minimumRequest; } - public int getFragmentSize() { + int getFragmentSize() { return fragmentSize; }
--- a/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamSampleSpecification.java Wed Dec 03 14:31:01 2008 +0000 +++ b/pulseaudio/src/java/org/classpath/icedtea/pulseaudio/StreamSampleSpecification.java Wed Dec 03 10:07:38 2008 -0500 @@ -39,7 +39,7 @@ import org.classpath.icedtea.pulseaudio.Stream.Format; -public class StreamSampleSpecification { +class StreamSampleSpecification { private Format format; private int rate; private int channels;