All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jaudiolibs.audioservers.javasound.JavasoundAudioServer Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2019 Neil C Smith.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details.
 *
 * You should have received a copy of the GNU General Public License version 2
 * along with this work; if not, see http://www.gnu.org/licenses/
 *
 *
 * Linking this work statically or dynamically with other modules is making a
 * combined work based on this work. Thus, the terms and conditions of the GNU
 * General Public License cover the whole combination.
 *
 * As a special exception, the copyright holders of this work give you permission
 * to link this work with independent modules to produce an executable,
 * regardless of the license terms of these independent modules, and to copy and
 * distribute the resulting executable under terms of your choice, provided that
 * you also meet, for each linked independent module, the terms and conditions of
 * the license of that module. An independent module is a module which is not
 * derived from or based on this work. If you modify this work, you may extend
 * this exception to your version of the work, but you are not obligated to do so.
 * If you do not wish to do so, delete this exception statement from your version.
 *
 * Please visit https://www.neilcsmith.net if you need additional information or
 * have any questions.
 */
package org.jaudiolibs.audioservers.javasound;

import java.util.logging.Logger;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
import org.jaudiolibs.audioservers.AudioClient;
import org.jaudiolibs.audioservers.AudioConfiguration;

/**
 * Implementation of an AudioServer using Javasound.
 *
 * @author Neil C Smith
 */
@Deprecated
public class JavasoundAudioServer extends JSAudioServer {

    private final static Logger LOG = Logger.getLogger(JavasoundAudioServer.class.getName());

    /**
     * Timing mode used by the server.
     *
     * For lowest latency try {@link #FramePosition} or {@link #Estimated}.
     */
    @Deprecated
    public static enum TimingMode {

        /**
         * Blocking timing mode. Block on write to output line. Javasound output
         * buffer is same size as internal buffers.
         */
        Blocking,
        /**
         * FramePosition timing mode. Use large Javasound output buffer.
         * Determine when to write to output line via getLongFramePosition().
         */
        FramePosition,
        /**
         * Estimated timing mode. Use large Javasound output buffer. Determine
         * when to write to output line by estimating position using
         * System.nanotime().
         */
        // @TODO Investigate whether xruns in underlying library are causing latency to increase.
        Estimated
    };

    private JavasoundAudioServer(Mixer inputMixer,
            Mixer outputMixer,
            JSTimingMode mode,
            AudioConfiguration context,
            AudioClient client) {
        super(inputMixer, outputMixer, mode, context, client);
    }

   
    /**
     * Create a JavasoundAudioServer.
     *
     *
     * @param inputMixer Javasound mixer to use for audio input. Can be null as
     * long as the context passed in requests no audio input channels.
     * @param outputMixer Javasound mixer to use for audio output.
     * @param context Requested audio configuration. Variable buffer size
     * property is ignored.
     * @param mode Timing mode to use. For lowest latency use
     * TimingMode.Estimated or TimingMode.FramePosition.
     * @param client Audio client to process every callback.
     * @return server
     * @throws IllegalArgumentException if requested context has no output
     * channels.
     */
    @Deprecated
    public static JavasoundAudioServer create(Mixer inputMixer, Mixer outputMixer,
            AudioConfiguration context, TimingMode mode, AudioClient client) {
        if (outputMixer == null || mode == null
                || context == null || client == null) {
            throw new NullPointerException();
        }
        if (inputMixer == null && context.getInputChannelCount() > 0) {
            throw new NullPointerException();
        }
        // must have real time output
        if (context.getOutputChannelCount() == 0) {
            throw new IllegalArgumentException();
        }
        // always fixed buffer size
        if (!context.isFixedBufferSize()) {
            context = new AudioConfiguration(context.getSampleRate(),
                    context.getInputChannelCount(),
                    context.getOutputChannelCount(),
                    context.getMaxBufferSize(),
                    true);
        }
        JSTimingMode jsMode = convertTimingMode(mode);
        return new JavasoundAudioServer(inputMixer, outputMixer, jsMode, context, client);
    }

    /**
     * Create a JavasoundAudioServer.
     *
     *
     * @param device Name of the device to use for audio input and output. If
     * null or an empty String, the first (default) device that provides the
     * required number of lines will be chosen. Otherwise a device will be
     * searched for that contains the provided String in its name.
     * @param context Requested audio configuration. Variable buffer size
     * property is ignored.
     * @param mode Timing mode to use. For lowest latency use
     * TimingMode.Estimated or TimingMode.FramePosition.
     * @param client Audio client to process every callback.
     * @return server
     * @throws Exception if requested context has no output channels, or if
     * suitable mixers cannot be found to satisfy the device name.
     */
    @Deprecated
    public static JavasoundAudioServer create(String device, AudioConfiguration context,
            TimingMode mode, AudioClient client) throws Exception {
        if (mode == null || client == null) {
            throw new NullPointerException();
        }
        if (device == null) {
            device = "";
        }
        // must have real time output
        if (context.getOutputChannelCount() == 0) {
            throw new IllegalArgumentException();
        }
        Mixer in = null;
        if (context.getInputChannelCount() > 0) {
            in = findInputMixer(device, context);
        }
        Mixer out = findOutputMixer(device, context);
        // always fixed buffer size
        if (!context.isFixedBufferSize()) {
            context = new AudioConfiguration(context.getSampleRate(),
                    context.getInputChannelCount(),
                    context.getOutputChannelCount(),
                    context.getMaxBufferSize(),
                    true);
        }
        JSTimingMode jsMode = convertTimingMode(mode);
        return new JavasoundAudioServer(in, out, jsMode, context, client);
    }

    private static Mixer findInputMixer(String device, AudioConfiguration conf) throws Exception {
        Mixer.Info[] infos = AudioSystem.getMixerInfo();
        Mixer mixer;
        DataLine.Info lineInfo = new DataLine.Info(TargetDataLine.class, getInputFormat(conf));
        for (int i = 0; i < infos.length; i++) {
            mixer = AudioSystem.getMixer(infos[i]);
            if (mixer.isLineSupported(lineInfo)) {
                if (infos[i].getName().indexOf(device) >= 0) {
                    LOG.finest("Found input mixer :\n" + infos[i]);
                    return mixer;
                }
            }
        }
        throw new Exception();
    }

    private static Mixer findOutputMixer(String device, AudioConfiguration conf) throws LineUnavailableException {
        Mixer.Info[] infos = AudioSystem.getMixerInfo();
        Mixer mixer;
        DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, getOutputFormat(conf));
        for (int i = 0; i < infos.length; i++) {
            mixer = AudioSystem.getMixer(infos[i]);
            if (mixer.isLineSupported(lineInfo)) {
                if (infos[i].getName().indexOf(device) >= 0) {
                    LOG.finest("Found output mixer :\n" + infos[i]);
                    return mixer;
                }
            }
        }
        throw new LineUnavailableException();
    }

    private static AudioFormat getInputFormat(AudioConfiguration conf) {
        return new AudioFormat(conf.getSampleRate(),
                16,
                conf.getInputChannelCount(),
                true,
                false);
    }

    private static AudioFormat getOutputFormat(AudioConfiguration conf) {
        return new AudioFormat(conf.getSampleRate(),
                16,
                conf.getOutputChannelCount(),
                true,
                false);
    }
    
    private static JSTimingMode convertTimingMode(TimingMode mode) {
        switch (mode) {
            case Estimated:
                return JSTimingMode.Estimated;
            case FramePosition:
                return JSTimingMode.FramePosition;
            default:
                return JSTimingMode.Blocking;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy