6938426: Concurrency bug in ALAW encoder causes random bursts of static/noise in output.
Reviewed-by: stayer
--- a/jdk/src/share/classes/com/sun/media/sound/AlawCodec.java Mon Feb 28 18:36:33 2011 +0300
+++ b/jdk/src/share/classes/com/sun/media/sound/AlawCodec.java Thu Mar 03 15:41:44 2011 +0300
@@ -52,9 +52,6 @@
private static final short seg_end [] = {0xFF, 0x1FF, 0x3FF,
0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
- private static final int tempBufferSize = 64;
- private byte tempBuffer [] = null;
-
/**
* Initializes the decode tables
*/
@@ -199,12 +196,9 @@
AudioFormat inputFormat = stream.getFormat();
if( inputFormat.matches(outputFormat) ) {
-
cs = stream;
} else {
-
cs = (AudioInputStream) (new AlawCodecStream(stream, outputFormat));
- tempBuffer = new byte[tempBufferSize];
}
return cs;
@@ -264,6 +258,10 @@
class AlawCodecStream extends AudioInputStream {
+ // tempBuffer required only for encoding (when encode is true)
+ private static final int tempBufferSize = 64;
+ private byte tempBuffer [] = null;
+
/**
* True to encode to a-law, false to decode to linear
*/
@@ -303,6 +301,7 @@
encodeFormat = outputFormat;
decodeFormat = inputFormat;
PCMIsBigEndian = inputFormat.isBigEndian();
+ tempBuffer = new byte[tempBufferSize];
}
if (PCMIsBigEndian) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/sampled/FileWriter/AlawEncoderSync.java Thu Mar 03 15:41:44 2011 +0300
@@ -0,0 +1,113 @@
+/**
+ * @test
+ * @bug 6938426
+ * @summary Tests that Alaw encoder works properly in multithreaded environment
+ * @author Alex Menkov
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+
+public class AlawEncoderSync {
+
+ static final int THREAD_COUNT = 20;
+
+ static final AudioFormat pcmFormat = new AudioFormat(8000f, 16, 2, true, false);
+ static final int STREAM_LENGTH = 10; // in seconds
+ static byte[] pcmBuffer;
+ static final AudioFormat alawFormat
+ = new AudioFormat(AudioFormat.Encoding.ALAW, 8000f, 8, 2, 2, 8000f, false);
+
+ static final ConversionThread[] threads = new ConversionThread[THREAD_COUNT];
+
+ public static void main(String[] args) {
+ preparePCMBuffer();
+ log("pcmStream size: " + pcmBuffer.length);
+
+ for (int i=0; i<THREAD_COUNT; i++) {
+ threads[i] = new ConversionThread(i);
+ threads[i].start();
+ }
+
+ for (int i=1; i<THREAD_COUNT; i++) {
+ try {
+ threads[i].join();
+ } catch (InterruptedException ex) {
+ log("Main thread was interrupted, exiting.");
+ return;
+ }
+ }
+
+ int failed = 0;
+ log("comparing result arrays...");
+ for (int i=1; i<THREAD_COUNT; i++) {
+ if (!Arrays.equals(threads[0].resultArray, threads[i].resultArray)) {
+ failed++;
+ log("NOT equals: 0 and " + i);
+ }
+ }
+ if (failed > 0) {
+ throw new RuntimeException("test FAILED");
+ }
+ log("test PASSED.");
+ }
+
+
+ static void preparePCMBuffer() {
+ pcmBuffer = new byte[STREAM_LENGTH * (int)pcmFormat.getSampleRate()
+ * (pcmFormat.getSampleSizeInBits() / 8) * pcmFormat.getChannels()];
+ for (int i=0; i<pcmBuffer.length; i++) {
+ pcmBuffer[i] = (byte)(Math.random() * 256.0 - 128.0);
+ }
+ }
+
+ static AudioInputStream createPCMStream() {
+ InputStream byteStream = new ByteArrayInputStream(pcmBuffer);
+ return new AudioInputStream(byteStream, pcmFormat, AudioSystem.NOT_SPECIFIED);
+ }
+
+ static class ConversionThread extends Thread {
+ public final int num;
+ public byte[] resultArray = null;
+ public ConversionThread(int num) {
+ this.num = num;
+ }
+ @Override
+ public void run() {
+ log("ConversionThread[" + num + "] started.");
+ try {
+ InputStream inStream = new ByteArrayInputStream(pcmBuffer);
+
+ AudioInputStream pcmStream = new AudioInputStream(
+ inStream, pcmFormat, AudioSystem.NOT_SPECIFIED);
+ AudioInputStream alawStream = AudioSystem.getAudioInputStream(alawFormat, pcmStream);
+
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+ int read = 0;
+ byte[] data = new byte[4096];
+ while((read = alawStream.read(data)) != -1) {
+ outStream.write(data, 0, read);
+ }
+ alawStream.close();
+ resultArray = outStream.toByteArray();
+ } catch (Exception ex) {
+ log("ConversionThread[" + num + "] exception:");
+ log(ex);
+ }
+ log("ConversionThread[" + num + "] completed.");
+ }
+ }
+
+ static void log(String s) {
+ System.out.println(s);
+ }
+
+ static void log(Exception ex) {
+ ex.printStackTrace(System.out);
+ }
+}