alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (AbstractDataLine.java)

This example Java source code file (AbstractDataLine.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

abstractdataline, abstractline, abstractmixer, audioformat, control, illegalstateexception, lineevent, lineunavailableexception, object

The AbstractDataLine.java Java example source code

/*
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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 (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.media.sound;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Control;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineUnavailableException;


/**
 * AbstractDataLine
 *
 * @author Kara Kytle
 */
abstract class AbstractDataLine extends AbstractLine implements DataLine {

    // DEFAULTS

    // default format
    private final AudioFormat defaultFormat;

    // default buffer size in bytes
    private final int defaultBufferSize;

    // the lock for synchronization
    protected final Object lock = new Object();

    // STATE

    // current format
    protected AudioFormat format;

    // current buffer size in bytes
    protected int bufferSize;

    protected boolean running = false;
    private boolean started = false;
    private boolean active = false;


    /**
     * Constructs a new AbstractLine.
     */
    protected AbstractDataLine(DataLine.Info info, AbstractMixer mixer, Control[] controls) {
        this(info, mixer, controls, null, AudioSystem.NOT_SPECIFIED);
    }

    /**
     * Constructs a new AbstractLine.
     */
    protected AbstractDataLine(DataLine.Info info, AbstractMixer mixer, Control[] controls, AudioFormat format, int bufferSize) {

        super(info, mixer, controls);

        // record the default values
        if (format != null) {
            defaultFormat = format;
        } else {
            // default CD-quality
            defaultFormat = new AudioFormat(44100.0f, 16, 2, true, Platform.isBigEndian());
        }
        if (bufferSize > 0) {
            defaultBufferSize = bufferSize;
        } else {
            // 0.5 seconds buffer
            defaultBufferSize = ((int) (defaultFormat.getFrameRate() / 2)) * defaultFormat.getFrameSize();
        }

        // set the initial values to the defaults
        this.format = defaultFormat;
        this.bufferSize = defaultBufferSize;
    }


    // DATA LINE METHODS

    public final void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
        //$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
        synchronized (mixer) {
            if (Printer.trace) Printer.trace("> AbstractDataLine.open(format, bufferSize) (class: "+getClass().getName());

            // if the line is not currently open, try to open it with this format and buffer size
            if (!isOpen()) {
                // make sure that the format is specified correctly
                // $$fb part of fix for 4679187: Clip.open() throws unexpected Exceptions
                Toolkit.isFullySpecifiedAudioFormat(format);

                if (Printer.debug) Printer.debug("  need to open the mixer...");
                // reserve mixer resources for this line
                //mixer.open(this, format, bufferSize);
                mixer.open(this);

                try {
                    // open the data line.  may throw LineUnavailableException.
                    implOpen(format, bufferSize);

                    // if we succeeded, set the open state to true and send events
                    setOpen(true);

                } catch (LineUnavailableException e) {
                    // release mixer resources for this line and then throw the exception
                    mixer.close(this);
                    throw e;
                }
            } else {
                if (Printer.debug) Printer.debug("  dataline already open");

                // if the line is already open and the requested format differs from the
                // current settings, throw an IllegalStateException
                //$$fb 2002-04-02: fix for 4661602: Buffersize is checked when re-opening line
                if (!format.matches(getFormat())) {
                    throw new IllegalStateException("Line is already open with format " + getFormat() +
                                                    " and bufferSize " + getBufferSize());
                }
                //$$fb 2002-07-26: allow changing the buffersize of already open lines
                if (bufferSize > 0) {
                    setBufferSize(bufferSize);
                }
            }

            if (Printer.trace) Printer.trace("< AbstractDataLine.open(format, bufferSize) completed");
        }
    }


    public final void open(AudioFormat format) throws LineUnavailableException {
        open(format, AudioSystem.NOT_SPECIFIED);
    }


    /**
     * This implementation always returns 0.
     */
    public int available() {
        return 0;
    }


    /**
     * This implementation does nothing.
     */
    public void drain() {
        if (Printer.trace) Printer.trace("AbstractDataLine: drain");
    }


    /**
     * This implementation does nothing.
     */
    public void flush() {
        if (Printer.trace) Printer.trace("AbstractDataLine: flush");
    }


    public final void start() {
        //$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
        synchronized(mixer) {
            if (Printer.trace) Printer.trace("> "+getClass().getName()+".start() - AbstractDataLine");

            // $$kk: 06.06.99: if not open, this doesn't work....???
            if (isOpen()) {

                if (!isStartedRunning()) {
                    mixer.start(this);
                    implStart();
                    running = true;
                }
            }
        }

        synchronized(lock) {
            lock.notifyAll();
        }

        if (Printer.trace) Printer.trace("< "+getClass().getName()+".start() - AbstractDataLine");
    }


    public final void stop() {

        //$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
        synchronized(mixer) {
            if (Printer.trace) Printer.trace("> "+getClass().getName()+".stop() - AbstractDataLine");

            // $$kk: 06.06.99: if not open, this doesn't work.
            if (isOpen()) {

                if (isStartedRunning()) {

                    implStop();
                    mixer.stop(this);

                    running = false;

                    // $$kk: 11.10.99: this is not exactly correct, but will probably work
                    if (started && (!isActive())) {
                        setStarted(false);
                    }
                }
            }
        }

        synchronized(lock) {
            lock.notifyAll();
        }

        if (Printer.trace) Printer.trace("< "+getClass().getName()+".stop() - AbstractDataLine");
    }

    // $$jb: 12.10.99: The official API for this is isRunning().
    // Per the denied RFE 4297981,
    // the change to isStarted() is technically an unapproved API change.
    // The 'started' variable is false when playback of data stops.
    // It is changed throughout the implementation with setStarted().
    // This state is what should be returned by isRunning() in the API.
    // Note that the 'running' variable is true between calls to
    // start() and stop().  This state is accessed now through the
    // isStartedRunning() method, defined below.  I have not changed
    // the variable names at this point, since 'running' is accessed
    // in MixerSourceLine and MixerClip, and I want to touch as little
    // code as possible to change isStarted() back to isRunning().

    public final boolean isRunning() {
        return started;
    }

    public final boolean isActive() {
        return active;
    }


    public final long getMicrosecondPosition() {

        long microseconds = getLongFramePosition();
        if (microseconds != AudioSystem.NOT_SPECIFIED) {
            microseconds = Toolkit.frames2micros(getFormat(), microseconds);
        }
        return microseconds;
    }


    public final AudioFormat getFormat() {
        return format;
    }


    public final int getBufferSize() {
        return bufferSize;
    }

    /**
     * This implementation does NOT change the buffer size
     */
    public final int setBufferSize(int newSize) {
        return getBufferSize();
    }

    /**
     * This implementation returns AudioSystem.NOT_SPECIFIED.
     */
    public final float getLevel() {
        return (float)AudioSystem.NOT_SPECIFIED;
    }


    // HELPER METHODS

    /**
     * running is true after start is called and before stop is called,
     * regardless of whether data is actually being presented.
     */
    // $$jb: 12.10.99: calling this method isRunning() conflicts with
    // the official API that was once called isStarted().  Since we
    // use this method throughout the implementation, I am renaming
    // it to isStartedRunning().  This is part of backing out the
    // change denied in RFE 4297981.

    final boolean isStartedRunning() {
        return running;
    }

    /**
     * This method sets the active state and generates
     * events if it changes.
     */
    final void setActive(boolean active) {

        if (Printer.trace) Printer.trace("> AbstractDataLine: setActive(" + active + ")");

        //boolean sendEvents = false;
        //long position = getLongFramePosition();

        synchronized (this) {

            //if (Printer.debug) Printer.debug("    AbstractDataLine: setActive: this.active: " + this.active);
            //if (Printer.debug) Printer.debug("                                 active: " + active);

            if (this.active != active) {
                this.active = active;
                //sendEvents = true;
            }
        }

        //if (Printer.debug) Printer.debug("                                 this.active: " + this.active);
        //if (Printer.debug) Printer.debug("                                 sendEvents: " + sendEvents);


        // $$kk: 11.19.99: take ACTIVE / INACTIVE / EOM events out;
        // putting them in is technically an API change.
        // do not generate ACTIVE / INACTIVE events for now
        // if (sendEvents) {
        //
        //      if (active) {
        //              sendEvents(new LineEvent(this, LineEvent.Type.ACTIVE, position));
        //      } else {
        //              sendEvents(new LineEvent(this, LineEvent.Type.INACTIVE, position));
        //      }
        //}
    }

    /**
     * This method sets the started state and generates
     * events if it changes.
     */
    final void setStarted(boolean started) {

        if (Printer.trace) Printer.trace("> AbstractDataLine: setStarted(" + started + ")");

        boolean sendEvents = false;
        long position = getLongFramePosition();

        synchronized (this) {

            //if (Printer.debug) Printer.debug("    AbstractDataLine: setStarted: this.started: " + this.started);
            //if (Printer.debug) Printer.debug("                                  started: " + started);

            if (this.started != started) {
                this.started = started;
                sendEvents = true;
            }
        }

        //if (Printer.debug) Printer.debug("                                  this.started: " + this.started);
        //if (Printer.debug) Printer.debug("                                  sendEvents: " + sendEvents);

        if (sendEvents) {

            if (started) {
                sendEvents(new LineEvent(this, LineEvent.Type.START, position));
            } else {
                sendEvents(new LineEvent(this, LineEvent.Type.STOP, position));
            }
        }
        if (Printer.trace) Printer.trace("< AbstractDataLine: setStarted completed");
    }


    /**
     * This method generates a STOP event and sets the started state to false.
     * It is here for historic reasons when an EOM event existed.
     */
    final void setEOM() {

        if (Printer.trace) Printer.trace("> AbstractDataLine: setEOM()");
        //$$fb 2002-04-21: sometimes, 2 STOP events are generated.
        // better use setStarted() to send STOP event.
        setStarted(false);
        if (Printer.trace) Printer.trace("< AbstractDataLine: setEOM() completed");
    }




    // OVERRIDES OF ABSTRACT LINE METHODS

    /**
     * Try to open the line with the current format and buffer size values.
     * If the line is not open, these will be the defaults.  If the
     * line is open, this should return quietly because the values
     * requested will match the current ones.
     */
    public final void open() throws LineUnavailableException {

        if (Printer.trace) Printer.trace("> "+getClass().getName()+".open() - AbstractDataLine");

        // this may throw a LineUnavailableException.
        open(format, bufferSize);
        if (Printer.trace) Printer.trace("< "+getClass().getName()+".open() - AbstractDataLine");
    }


    /**
     * This should also stop the line.  The closed line should not be running or active.
     * After we close the line, we reset the format and buffer size to the defaults.
     */
    public final void close() {
        //$$fb 2001-10-09: Bug #4517739: avoiding deadlock by synchronizing to mixer !
        synchronized (mixer) {
            if (Printer.trace) Printer.trace("> "+getClass().getName()+".close() - in AbstractDataLine.");

            if (isOpen()) {

                // stop
                stop();

                // set the open state to false and send events
                setOpen(false);

                // close resources for this line
                implClose();

                // release mixer resources for this line
                mixer.close(this);

                // reset format and buffer size to the defaults
                format = defaultFormat;
                bufferSize = defaultBufferSize;
            }
        }
        if (Printer.trace) Printer.trace("< "+getClass().getName()+".close() - in AbstractDataLine");
    }


    // IMPLEMENTATIONS OF ABSTRACT LINE ABSTRACE METHODS


    // ABSTRACT METHODS

    abstract void implOpen(AudioFormat format, int bufferSize) throws LineUnavailableException;
    abstract void implClose();

    abstract void implStart();
    abstract void implStop();
}

Other Java examples (source code examples)

Here is a short list of links related to this Java AbstractDataLine.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.