Kyle
Kyle

Reputation: 151

Cannot read from TargetDataLine

So, I've been working on a learning type project to get audio data from a line in and render it to my speakers. Now, I'm on both my last straw and last couple lines of code and I don't know what will come first. Once both the data lines are set up, I try to read the TargetDataLine into a byte array, and the compiler throws a nullPointerException. The error is tracked to Stream.java:138 which is public static void play(). I'm not sure my Thread is set up right either, but let's try to focus on the topic at hand for now. I'm essentially just trying to read the Line In and write it to the Speakers, and any advice would be great.

Code:

package moshi;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;

/**
 * @author KN
 * @version 1.0 Build 1 October 25, 2013
 * 
 *          This concurrent process sets up and controls the streaming of audio
 *          data via input and output buffers.
 * 
 * @see {@link Thread}, {@link AudioSystem}, {@link TargetDataLine},
 *      {@link SourceDataLine}
 */

public class Stream extends Thread {

    /** The {@link AudioFormat} used in encoding/decoding streaming audio data */
    public final static AudioFormat audioFormat = new AudioFormat(44100, 8, 1, true, true);

    /**
     * {@link String} describing the name of the audio device to be used.
     * <p>
     * Example: "Line In", "Microphone"
     */
    private static String INPUT = "Line In";
    /**
     * {@link String} describing the name of the audio device to be used.
     * <p>
     * Example: "Speakers", "Line Out"
     */
    private static String OUTPUT = "Speakers";

    /**
     * {@link #PROCESSING_BUFFER} is a buffer used for receiving audio data
     * 
     * @see TargetDataLine
     */
    private static TargetDataLine PROCESSING_BUFFER;
    /**
     * {@link #RENDERING_BUFFER} is a buffer used for writing audio data
     * 
     * @see SourceDataLine
     */
    private static SourceDataLine RENDERING_BUFFER;
    /** {@link Integer} specifying the buffer sizes in bytes */
    private static int BUFFER_SIZE = 2048;
    /** {@link Byte[]} for holding raw audio data */
    private static byte[] READ_BUFFER;

    /**
     * Initiates the audio hardware read/write buffers into
     * {@link TargetDataLine}s and {@link SourceDataLine}s respectively.
     * 
     * @see {@link TargetDataLine}, {@link SourceDataLine}
     */
    public Stream() {
        setProcessingBuffer();
        setRenderingBuffer();
    }

    /**
     * Queries input Lines and stores the {@link TargetDataLine} at
     * {@link #PROCESSING_BUFFER}
     * 
     * @see {@link AudioSystem}, {@link Line}, {@link TargetDataLine},
     *      {@link Mixer}
     */
    private void setProcessingBuffer() {
        final Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
        for (final Mixer.Info info : mixerInfos) {
            final Mixer mixer = AudioSystem.getMixer(info);
            final Line.Info[] targetLineInfos = mixer.getTargetLineInfo();
            for (final Line.Info targetLineInfo : targetLineInfos) {
                if (targetLineInfo.getLineClass() == javax.sound.sampled.TargetDataLine.class
                        && info.getName().startsWith(Stream.INPUT)) {
                    try {
                        Stream.PROCESSING_BUFFER = (TargetDataLine) mixer.getLine(targetLineInfo);
                        System.out.println(targetLineInfo.getLineClass() + ": " + info.getName() + " ["
                                + Stream.PROCESSING_BUFFER + "]");
                    } catch (LineUnavailableException e) {
                        e.printStackTrace();
                    }
                } else {
                }
            }
        }
    }

    /**
     * Queries output Lines and stores the {@link SourceDataLine} at
     * {@link #RENDERING_BUFFER}
     * 
     * @see {@link AudioSystem}, {@link Line}, {@link SourceDataLine},
     *      {@link Mixer}
     */
    private void setRenderingBuffer() {
        final Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo();
        for (Mixer.Info info : mixerInfos) {
            final Mixer mixer = AudioSystem.getMixer(info);
            final Line.Info[] sourceLineInfos = mixer.getSourceLineInfo();
            for (final Line.Info sourceLineInfo : sourceLineInfos) {
                if (sourceLineInfo.getLineClass() == javax.sound.sampled.SourceDataLine.class
                        && info.getName().startsWith(Stream.OUTPUT)) {
                    try {
                        Stream.RENDERING_BUFFER = (SourceDataLine) mixer.getLine(sourceLineInfo);
                        System.out.println(sourceLineInfo.getLineClass() + ": " + info.getName() + " ["
                                + Stream.RENDERING_BUFFER + "]");
                    } catch (LineUnavailableException e) {
                        e.printStackTrace();
                    }
                } else {
                }
            }
        }
    }

    /**
     * Opens buffers {@link #PROCESSING_BUFFER} and {@link #RENDERING_BUFFER}
     * for reading/writing
     */
    public static void play() {
        try {
            if (!Stream.PROCESSING_BUFFER.isOpen()) {
                Stream.PROCESSING_BUFFER.open(Stream.audioFormat);
            }
            if (!Stream.RENDERING_BUFFER.isOpen()) {
                Stream.RENDERING_BUFFER.open(Stream.audioFormat);
                Stream.RENDERING_BUFFER.start();
            }
            while (Stream.RENDERING_BUFFER.isOpen()) {
                Stream.PROCESSING_BUFFER.read(Stream.READ_BUFFER, 0, Stream.BUFFER_SIZE);
                System.out.println(Stream.READ_BUFFER.length);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Stops buffers {@link #PROCESSING_BUFFER} and {@link #RENDERING_BUFFER}
     * from reading/writing
     */
    public static void pause() {
        if (Stream.PROCESSING_BUFFER.isOpen()) {
            Stream.PROCESSING_BUFFER.close();
        }
        if (Stream.RENDERING_BUFFER.isOpen()) {
            Stream.RENDERING_BUFFER.stop();
            Stream.RENDERING_BUFFER.close();
        }
    }

    /** {@inheritDoc} */
    @Override
    public void run() {
    }
}

The output from the system and the error stack trace say:

interface javax.sound.sampled.TargetDataLine: Line In (Realtek High Definitio [com.sun.media.sound.DirectAudioDevice$DirectTDL@18dd7404]
interface javax.sound.sampled.SourceDataLine: Speakers (Realtek High Definition Audio) [com.sun.media.sound.DirectAudioDevice$DirectSDL@3639b3a2]
java.lang.NullPointerException
    at com.sun.media.sound.DirectAudioDevice$DirectTDL.read(Unknown Source)
    at moshi.Stream.play(Stream.java:138)
    at moshi.Controls$1.actionPerformed(Controls.java:38)
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
    at java.awt.Component.processMouseEvent(Unknown Source)
    at javax.swing.JComponent.processMouseEvent(Unknown Source)
    at java.awt.Component.processEvent(Unknown Source)
    at java.awt.Container.processEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.awt.EventQueue$4.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

Upvotes: 1

Views: 1137

Answers (1)

&#211;scar L&#243;pez
&#211;scar L&#243;pez

Reputation: 236122

You never initialized the READ_BUFFER variable in your code, you must instantiate it with an appropriate size:

READ_BUFFER = new byte[BUFFER_SIZE]; // I guess this was the intended size

Upvotes: 3

Related Questions