JDK-4347309 : Simultaneous capture/playback of audio does not work on Linux.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.sound
  • Affected Version: 1.3.0,1.3.1
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux,windows_2000
  • CPU: x86
  • Submitted: 2000-06-21
  • Updated: 2002-11-21
  • Resolved: 2002-11-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 mantisFixed
Description

Name: sl110371			Date: 06/21/2000


java version "1.3.0beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0beta-b07)
Java HotSpot(TM) Client VM (build 1.3.0beta-b04, mixed mode)

Operating System: Red Hat Linux 6.1 and 6.2

Environment (tried two different machines):
Machine 1: Dell Dimension XPS R400 running Red Hat Linux 6.1, with 256 MB ECC
SDRAM, Ensonic AudioPCI model es1371 sound card.

Machine 2: PC running Red Hat Linux 6.2, Intel 440BX-2 motherboard, Celeron 400
MHz, 384 MB SDRAM, with SB Live! (emu10k1) sound card.

Both sound cards support full-duplex operation.

  Description:

Simultaneous capture/playback (full-duplex audio) appears to be broken in the
Linux release of JDK 1.3.0. I am able to run the Sun Java Sound demos, which do
not require full-duplex operation. The attached code illustrates the problem.
This program runs successfully under the Sun JDK 1.3 on Windows 2000, but does
not work under Linux. I have tried different formats, samples rates, buffers
sizes, but nothing works.

Error messages encountered: Program prints the following output and then hangs.
Opened playback line.
Opened capture line.
Capture started.
Playback started.
Trying to read data


More Java Sound examples that also require simultaneous capture/playback (and
also do not work) can be found at:
http://rupert.informatik.uni-stuttgart.de/~pfistere/jsexamples/


Example code: (Run it by typing javac Duplex1.java; java Duplex1)



import	javax.sound.sampled.DataLine;
import	javax.sound.sampled.SourceDataLine;
import	javax.sound.sampled.TargetDataLine;
import	javax.sound.sampled.AudioFormat;
import	javax.sound.sampled.AudioSystem;
import	javax.sound.sampled.LineUnavailableException;
import	javax.sound.sampled.AudioFileFormat;


/**  Duplex1.java written by Brian K. Vogel (###@###.###)
 *   Purpose: Test full-duplex capture/playback. Capture from mic/line-in
 *            and play captured audio to speaker.
 */
public class Duplex1
{
	public static void main(String[] args)
	{
	    TargetDataLine	targetLine;
	    SourceDataLine	sourceLine;
	    AudioFormat	audioFormat = new AudioFormat( 44100.0F, 16, 2, true, true);
	
		try
		{
		    
		DataLine.Info	sourceDataLineInfo = new DataLine.Info(SourceDataLine.class,
audioFormat);
		sourceLine = (SourceDataLine) AudioSystem.getLine(sourceDataLineInfo);
		sourceLine.open(audioFormat);
		System.out.println("Opened playback line.");
		
		DataLine.Info	targetDateLineInfo = new DataLine.Info(TargetDataLine.class,
audioFormat);
		targetLine = (TargetDataLine) AudioSystem.getLine(targetDateLineInfo);
		targetLine.open(audioFormat);
		System.out.println("Opened capture line.");

		// Start capture.
		targetLine.start();
		System.out.println("Capture started.");
		// Start playback.
		sourceLine.start();
		System.out.println("Playback started.");

		int buffSize = 4096;
		byte[]	sampleBuffer = new byte[buffSize];
		int bytesRead;
		while(true) {
		    System.out.println("Trying to read data");
		    bytesRead = targetLine.read(sampleBuffer, 0, buffSize);
		    System.out.println("Read data");
		    System.out.println("Trying to write data");
		    sourceLine.write(sampleBuffer, 0, bytesRead);
		    System.out.println("Wrote data");
		    System.out.println("************************");
		}

		}
		catch (LineUnavailableException e)
		{
			e.printStackTrace();
			System.exit(1);
		}

	}
}
(Review ID: 105809) 
======================================================================

Name: krC82822			Date: 01/13/2001


13 Jan 2001, evall127@eng -- seems related to #'s 4257234 & 4347309 (one
of which should be closed as a duplicate of the other).
-----------------
java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)


I swear I read that Java Sound API was supposed to be able to do full duplex if
the card supports it.  I know my card supports it, but I cannot get it to work.
This may not be a bug; maybe I just don't know how to do it, but I haven't been
able to find any information on how to do simultaneous playback and record
correctly.  Even though I'm using the same *instance* of AudioFormat to open
both lines, I consistently get the following exception:

javax.sound.sampled.LineUnavailableException: Requested format incompatible with
already established device format: PCM_SIGNED, 44100.0 Hz, 16 bit, stereo,
big-endian, audio data
	at com.sun.media.sound.AbstractMixer.open(AbstractMixer.java:271)
	at com.sun.media.sound.SimpleInputDevice.open(SimpleInputDevice.java:528)
	at com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:83)
	at com.sun.media.sound.AbstractDataLine.open(AbstractDataLine.java:114)
	at SimpleMultiTracker$TinyRecorder.fileRecord(SimpleMultiTracker.java:138)
	at SimpleMultiTracker$TinyRecorder.run(SimpleMultiTracker.java:102)
	at java.lang.Thread.run(Thread.java:484)

Here's the sample program I've written while trying to figure out how this
works.  Please pardon the general crapiness of it; I'll design it right when I
figure out the details:

/******************************************************************************/
import java.io.*;
import javax.sound.sampled.*;

public class SimpleMultiTracker
{
    protected AudioFormat _audioFormat;

    public static void main(String[] args)
    {
        new SimpleMultiTracker().begin(args);

        return;
    }

    protected static class TinyPlayer implements Runnable
    {
        protected SimpleMultiTracker _parent;
        protected String _filename;

        public TinyPlayer(SimpleMultiTracker parent, String filename)
        {
            _parent = parent;
            _filename = filename;
        }

        public void run()
        {
            filePlayback(_filename);
        }

        protected void filePlayback(String filename)
        {
            SourceDataLine line = null;
            File file = null;
            AudioFileFormat fileFormat = null;
            AudioFormat audioFormat = null;
            DataLine.Info info = null;

            try
            {
                file = new File(filename);
                fileFormat = AudioSystem.getAudioFileFormat(file);
                // this is the AudioFormat we expect to use for recording as
                // well.
                audioFormat = fileFormat.getFormat();
                _parent.setAudioFormat(audioFormat);
                System.out.println(audioFormat);
                System.out.flush();
                info = new DataLine.Info(SourceDataLine.class, audioFormat);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }

            if(!AudioSystem.isLineSupported(info))
            {
                System.err.println("Line not supported: " + info);
                System.err.flush();
            }

            try
            {
                line = (SourceDataLine)AudioSystem.getLine(info);
                line.open(audioFormat);
                line.start();

                int bytesRead = 0;
                byte[] buf = new byte[1024];
                FileInputStream in = new FileInputStream(file);
                for(int total = 0; total < file.length() && bytesRead != -1;)
                {
                    bytesRead = in.read(buf, 0, 1024);
                    total += bytesRead;
                    line.write(buf, 0, bytesRead);
                }

                line.drain();
                line.stop();
                line.close();
                line = null;
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    protected static class TinyRecorder implements Runnable
    {
        protected SimpleMultiTracker _parent;
        protected String _filename;

        public TinyRecorder(SimpleMultiTracker parent, String filename)
        {
            _parent = parent;
            _filename = filename;
        }

        public void run()
        {
            fileRecord(_filename);
        }

        protected void fileRecord(String filename)
        {
            TargetDataLine lineIn = null;
            AudioInputStream in = null;
            // clearly I'm using the same AudioFormat, because I'm referring
            // to the same instance that the player is using.  Naturally I
            // I tried it with a separate instance initially, but when that
            // didn't work, I tried this, which also didn't work.
            AudioFormat format = null;
            while(format == null)
            {
                format = _parent.getAudioFormat();
                try{Thread.sleep(1000);}
                catch(Exception e)
                {}
            }

            DataLine.Info info =
                new DataLine.Info(TargetDataLine.class, format);
            File file = null;

            try
            {
                file = new File(filename);
                lineIn = (TargetDataLine)AudioSystem.getLine(info);
                in = new AudioInputStream(lineIn);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }

            try
            {
                lineIn.open(format);
                lineIn.start();

                AudioSystem.write(in, AudioFileFormat.Type.WAVE, file);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    protected void begin(String[] args)
    {
        if(args.length != 2)
        {
            System.err.println("usage: " + getClass().getName() +
                               " fileToPlayback fileToRecord");
            System.err.flush();
            System.exit(1);
        }

        Thread player = new Thread(new TinyPlayer(this, args[0]));
        Thread recorder = new Thread(new TinyRecorder(this, args[1]));

        player.start();
        recorder.start();
    }

    protected AudioFormat getAudioFormat()
    {
        return _audioFormat;
    }

    protected void setAudioFormat(AudioFormat audioFormat)
    {
        _audioFormat = audioFormat;
    }
}
(Review ID: 114260)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis FIXED IN: mantis INTEGRATED IN: mantis
14-06-2004

EVALUATION ###@###.### 2002-11-02 Changed synopsis to include Linux, since this is a linux-specific bug. This bug should be fixed with ALSA support in 1.4.2 (of course, ALSA 0.9 needs to be installed on the Linux system).
11-06-2004

PUBLIC COMMENTS Simultaneous capture/playback of audio does not work on Linux.
10-06-2004