Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/media/sound/DataPusher.java
38924 views
/*1* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.media.sound;2627import java.util.Arrays;2829import javax.sound.sampled.*;3031/**32* Class to write an AudioInputStream to a SourceDataLine.33* Was previously an inner class in various classes like JavaSoundAudioClip34* and sun.audio.AudioDevice.35* It auto-opens and closes the SourceDataLine.36*37* @author Kara Kytle38* @author Florian Bomers39*/4041public final class DataPusher implements Runnable {4243private static final int AUTO_CLOSE_TIME = 5000;44private static final boolean DEBUG = false;4546private final SourceDataLine source;47private final AudioFormat format;4849// stream as source data50private final AudioInputStream ais;5152// byte array as source data53private final byte[] audioData;54private final int audioDataByteLength;55private int pos;56private int newPos = -1;57private boolean looping;5859private Thread pushThread = null;60private int wantedState;61private int threadState;6263private final int STATE_NONE = 0;64private final int STATE_PLAYING = 1;65private final int STATE_WAITING = 2;66private final int STATE_STOPPING = 3;67private final int STATE_STOPPED = 4;68private final int BUFFER_SIZE = 16384;6970public DataPusher(SourceDataLine sourceLine, AudioFormat format, byte[] audioData, int byteLength) {71this(sourceLine, format, null, audioData, byteLength);72}7374public DataPusher(SourceDataLine sourceLine, AudioInputStream ais) {75this(sourceLine, ais.getFormat(), ais, null, 0);76}7778private DataPusher(final SourceDataLine source, final AudioFormat format,79final AudioInputStream ais, final byte[] audioData,80final int audioDataByteLength) {81this.source = source;82this.format = format;83this.ais = ais;84this.audioDataByteLength = audioDataByteLength;85this.audioData = audioData == null ? null : Arrays.copyOf(audioData,86audioData.length);87}8889public synchronized void start() {90start(false);91}9293public synchronized void start(boolean loop) {94if (DEBUG || Printer.debug) Printer.debug("> DataPusher.start(loop="+loop+")");95try {96if (threadState == STATE_STOPPING) {97// wait that the thread has finished stopping98if (DEBUG || Printer.trace)Printer.trace("DataPusher.start(): calling stop()");99stop();100}101looping = loop;102newPos = 0;103wantedState = STATE_PLAYING;104if (!source.isOpen()) {105if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.open()");106source.open(format);107}108if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");109source.flush();110if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.start()");111source.start();112if (pushThread == null) {113if (DEBUG || Printer.debug) Printer.debug("DataPusher.start(): Starting push");114pushThread = JSSecurityManager.createThread(this,115null, // name116false, // daemon117-1, // priority118true); // doStart119}120notifyAll();121} catch (Exception e) {122if (DEBUG || Printer.err) e.printStackTrace();123}124if (DEBUG || Printer.debug) Printer.debug("< DataPusher.start(loop="+loop+")");125}126127128public synchronized void stop() {129if (DEBUG || Printer.debug) Printer.debug("> DataPusher.stop()");130if (threadState == STATE_STOPPING131|| threadState == STATE_STOPPED132|| pushThread == null) {133if (DEBUG || Printer.debug) Printer.debug("DataPusher.stop(): nothing to do");134return;135}136if (DEBUG || Printer.debug) Printer.debug("DataPusher.stop(): Stopping push");137138wantedState = STATE_WAITING;139if (source != null) {140if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");141source.flush();142}143notifyAll();144int maxWaitCount = 50; // 5 seconds145while ((maxWaitCount-- >= 0) && (threadState == STATE_PLAYING)) {146try {147wait(100);148} catch (InterruptedException e) { }149}150if (DEBUG || Printer.debug) Printer.debug("< DataPusher.stop()");151}152153synchronized void close() {154if (source != null) {155if (DEBUG || Printer.trace)Printer.trace("DataPusher.close(): source.close()");156source.close();157}158}159160/**161* Write data to the source data line.162*/163public void run() {164byte[] buffer = null;165boolean useStream = (ais != null);166if (useStream) {167buffer = new byte[BUFFER_SIZE];168} else {169buffer = audioData;170}171while (wantedState != STATE_STOPPING) {172//try {173if (wantedState == STATE_WAITING) {174// wait for 5 seconds - maybe the clip is to be played again175if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): waiting 5 seconds");176try {177synchronized(this) {178threadState = STATE_WAITING;179wantedState = STATE_STOPPING;180wait(AUTO_CLOSE_TIME);181}182} catch (InterruptedException ie) {}183if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): waiting finished");184continue;185}186if (newPos >= 0) {187pos = newPos;188newPos = -1;189}190threadState = STATE_PLAYING;191int toWrite = BUFFER_SIZE;192if (useStream) {193try {194pos = 0; // always write from beginning of buffer195// don't use read(byte[]), because some streams196// may not override that method197toWrite = ais.read(buffer, 0, buffer.length);198} catch (java.io.IOException ioe) {199// end of stream200toWrite = -1;201}202} else {203if (toWrite > audioDataByteLength - pos) {204toWrite = audioDataByteLength - pos;205}206if (toWrite == 0) {207toWrite = -1; // end of "stream"208}209}210if (toWrite < 0) {211if (DEBUG || Printer.debug) Printer.debug("DataPusher.run(): Found end of stream");212if (!useStream && looping) {213if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): setting pos back to 0");214pos = 0;215continue;216}217if (DEBUG || Printer.debug)Printer.debug("DataPusher.run(): calling drain()");218wantedState = STATE_WAITING;219source.drain();220continue;221}222if (DEBUG || Printer.debug) Printer.debug("> DataPusher.run(): Writing " + toWrite + " bytes");223int bytesWritten = source.write(buffer, pos, toWrite);224pos += bytesWritten;225if (DEBUG || Printer.debug) Printer.debug("< DataPusher.run(): Wrote " + bytesWritten + " bytes");226}227threadState = STATE_STOPPING;228if (DEBUG || Printer.debug)Printer.debug("DataPusher: closing device");229if (Printer.trace)Printer.trace("DataPusher: source.flush()");230source.flush();231if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.stop()");232source.stop();233if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.flush()");234source.flush();235if (DEBUG || Printer.trace)Printer.trace("DataPusher: source.close()");236source.close();237threadState = STATE_STOPPED;238synchronized (this) {239pushThread = null;240notifyAll();241}242if (DEBUG || Printer.debug)Printer.debug("DataPusher:end of thread");243}244245} // class DataPusher246247248