SourceDataLine getSourceDataLine(AudioFormat format, int bufferSize) { SourceDataLine line = null; DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); if (AudioSystem.isLineSupported(info)) { try { if (outputMixer == null) { line = (SourceDataLine) AudioSystem.getLine(info); } else { line = (SourceDataLine) outputMixer.getLine(info); } // remember that time you spent, like, an entire afternoon fussing // with this buffer size to try to get the latency decent on Linux? // Yah, don't fuss with this anymore, ok? line.open(format, bufferSize * format.getFrameSize() * 4); if (line.isOpen()) { debug( "SourceDataLine is " + line.getClass().toString() + "\n" + "Buffer size is " + line.getBufferSize() + " bytes.\n" + "Format is " + line.getFormat().toString() + "."); return line; } } catch (LineUnavailableException e) { error("Couldn't open the line: " + e.getMessage()); } } error("Unable to return a SourceDataLine: unsupported format - " + format.toString()); return line; }
private void startSpeaker(AudioFormat format) throws LineUnavailableException { speaker.open(format, bufferSize); int actualBufferSize = speaker.getBufferSize(); if (bufferSize != actualBufferSize) { Logger.println( "Speaker set buffer to " + bufferSize + " but actual size is " + actualBufferSize); bufferSize = actualBufferSize; } if (Logger.logLevel >= Logger.LOG_MOREINFO) { Logger.println( "Speaker using " + getBufferSizeMillis(actualBufferSize) + " millisecond buffer " + actualBufferSize + " bytes"); } speaker.start(); flush(); // println("speaker started"); }
public int getFramePosition() { long timeSinceLastPositionSet = System.currentTimeMillis() - timelastPositionSet; int size = dataLine.getBufferSize() * (format.getChannels() / 2) / bufferUpdateFactor; int framesSinceLast = (int) ((timeSinceLastPositionSet / 1000f) * dataLine.getFormat().getFrameRate()); int framesRemainingTillTime = size - framesSinceLast; return framePosition - framesRemainingTillTime; }
public SourceDataLine getOutputLine(AudioFormat format) throws LineUnavailableException { SourceDataLine out; DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); out = (SourceDataLine) mixer.getLine(info); out.open(format, out.getBufferSize()); return out; }
/** @see com.groovemanager.thread.ProgressThread#init() */ protected void init() throws InitException { analysisLine = unit.getAnalysisLine(); try { analysisLine.open(); } catch (LineUnavailableException e) { e.printStackTrace(); cancelOperation(); } if (!in.getFormat().equals(analysisLine.getFormat())) { if (AudioSystem.isConversionSupported(analysisLine.getFormat(), in.getFormat())) in = AudioSystem.getAudioInputStream(analysisLine.getFormat(), in); else throw new InitException( "Unable to process audio data:\nConversion from " + in.getFormat() + " to " + analysisLine.getFormat() + " not supported."); } buffer = new byte[analysisLine.getBufferSize()]; }
/** Opens the line. */ protected void openLine() throws LineUnavailableException { if (m_line != null) { AudioFormat audioFormat = m_audioInputStream.getFormat(); int buffersize = lineBufferSize; if (buffersize <= 0) { buffersize = m_line.getBufferSize(); } m_lineCurrentBufferSize = buffersize; m_line.open(audioFormat, buffersize); log.info("Open Line : BufferSize=" + buffersize); /*-- Display supported controls --*/ Control[] c = m_line.getControls(); for (int p = 0; p < c.length; p++) { log.info("Controls : " + c[p].toString()); } /*-- Is Gain Control supported ? --*/ if (m_line.isControlSupported(FloatControl.Type.MASTER_GAIN)) { m_gainControl = (FloatControl) m_line.getControl(FloatControl.Type.MASTER_GAIN); log.info( "Master Gain Control : [" + m_gainControl.getMinimum() + "," + m_gainControl.getMaximum() + "] " + m_gainControl.getPrecision()); } /*-- Is Pan control supported ? --*/ if (m_line.isControlSupported(FloatControl.Type.PAN)) { m_panControl = (FloatControl) m_line.getControl(FloatControl.Type.PAN); log.info( "Pan Control : [" + m_panControl.getMinimum() + "," + m_panControl.getMaximum() + "] " + m_panControl.getPrecision()); } } }
public int getBufferSize() { return dataLine.getBufferSize(); }
/** * Main loop. * * <p>Player Status == STOPPED || SEEKING => End of Thread + Freeing Audio Ressources.<br> * Player Status == PLAYING => Audio stream data sent to Audio line.<br> * Player Status == PAUSED => Waiting for another status. */ public void run() { log.info("Thread Running"); int nBytesRead = 1; byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; int readIndex = 0; // 所有读进缓冲区的数量 int writeIndex = 0; // 所有写出数量 // Lock stream while playing. synchronized (m_audioInputStream) { boolean buffering = false; // Main play/pause loop. while ((nBytesRead != -1) && (m_status != STOPPED) && (m_status != SEEKING) && (m_status != UNKNOWN)) { if (m_status == PLAYING) { // Play. try { nBytesRead = m_audioInputStream.read(abData, 0, abData.length); if (nBytesRead >= 0) { byte[] pcm = new byte[nBytesRead]; System.arraycopy(abData, 0, pcm, 0, nBytesRead); if (m_line.available() >= m_line.getBufferSize()) { // buffering = true; log.fine("缓冲区空虚 : " + m_line.available() + "/" + m_line.getBufferSize()); } // if(m_line.available()==0){ // buffering=false; // } if (buffering == false) { int nBytesWritten = m_line.write(abData, 0, nBytesRead); // Compute position in bytes in encoded stream. int nEncodedBytes = getEncodedStreamPosition(); // Notify listeners Iterator<BasicPlayerListener> it = laucher.getBasicPlayerListeners().iterator(); while (it.hasNext()) { BasicPlayerListener bpl = it.next(); if (m_audioInputStream instanceof PropertiesContainer) { // Pass audio parameters such as instant bitrate, ... Map properties = ((PropertiesContainer) m_audioInputStream).properties(); bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, properties); } else { bpl.progress(nEncodedBytes, m_line.getMicrosecondPosition(), pcm, empty_map); } } } } } catch (IOException e) { log.log(Level.SEVERE, "Thread cannot run()", e); m_status = STOPPED; notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null); } // Nice CPU usage. if (threadSleep > 0) { try { Thread.sleep(threadSleep); } catch (InterruptedException e) { log.log(Level.SEVERE, "Thread cannot sleep(" + threadSleep + ")", e); } } } else { synchronized (m_audioInputStream) { try { log.log(Level.INFO, "状态是不正在播放,要无限期的等待了....."); m_audioInputStream.wait(); log.log(Level.INFO, "状态改过来了,等待被唤醒了......."); } catch (InterruptedException ex) { Logger.getLogger(BasicPlayer.class.getName()).log(Level.SEVERE, null, ex); } } // Pause // try { // Thread.sleep(500); // } catch (InterruptedException e) { // log.log(Level.SEVERE, "Thread cannot sleep(500)", e); // } } } // Free audio resources. if (m_line != null) { m_line.drain(); m_line.stop(); m_line.close(); m_line = null; } // Notification of "End Of Media" if (nBytesRead == -1) { notifyEvent(BasicPlayerEvent.EOM, getEncodedStreamPosition(), -1, null); } // Close stream. closeStream(); } m_status = STOPPED; notifyEvent(BasicPlayerEvent.STOPPED, getEncodedStreamPosition(), -1, null); log.info("Thread completed"); }
/** * Single audio channel playback with automatic starting and stopping of the underlying * sourcedataline specified by the mixer and mixer channel arguments. * * <p>Maintains an internal non-blocking audio packet queue and processes this queue 25 times a * second (every 40 ms). * * @param threadPoolManager for assigning buffer processing schedule task * @param mixer to obtain source data line * @param mixerChannel either mono or left/right stereo * @param audioFormat to use during playback * @param lineInfo to use when obtaining the source data line * @param requestedBufferSize of approximately 1 second of audio */ public AudioOutput( ThreadPoolManager threadPoolManager, Mixer mixer, MixerChannel mixerChannel, AudioFormat audioFormat, Line.Info lineInfo, int requestedBufferSize) { mThreadPoolManager = threadPoolManager; mMixer = mixer; mMixerChannel = mixerChannel; try { mOutput = (SourceDataLine) mMixer.getLine(lineInfo); if (mOutput != null) { mOutput.open(audioFormat, requestedBufferSize); // Start threshold: buffer is full with 10% or less of capacity remaining mBufferStartThreshold = (int) (mOutput.getBufferSize() * 0.10); // Stop threshold: buffer is empty with 90% or more capacity available mBufferStopThreshold = (int) (mOutput.getBufferSize() * 0.90); mOutput.addLineListener(this); if (mOutput != null) { try { Control gain = mOutput.getControl(FloatControl.Type.MASTER_GAIN); mGainControl = (FloatControl) gain; } catch (IllegalArgumentException iae) { mLog.warn( "Couldn't obtain MASTER GAIN control for stereo line [" + mixer.getMixerInfo().getName() + " | " + getChannelName() + "]"); } try { Control mute = mOutput.getControl(BooleanControl.Type.MUTE); mMuteControl = (BooleanControl) mute; } catch (IllegalArgumentException iae) { mLog.warn( "Couldn't obtain MUTE control for stereo line [" + mixer.getMixerInfo().getName() + " | " + getChannelName() + "]"); } /* Run the queue processor task every 40 milliseconds or 25 times a second */ mProcessorTask = mThreadPoolManager.scheduleFixedRate( ThreadType.AUDIO_PROCESSING, new BufferProcessor(), 40, TimeUnit.MILLISECONDS); } mAudioStartEvent = new AudioEvent(AudioEvent.Type.AUDIO_STARTED, getChannelName()); mAudioStopEvent = new AudioEvent(AudioEvent.Type.AUDIO_STOPPED, getChannelName()); mCanProcessAudio = true; } } catch (LineUnavailableException e) { mLog.error( "Couldn't obtain audio source data line for " + "audio output - mixer [" + mMixer.getMixerInfo().getName() + "]"); } }