// Copyright 2014-2025 Jesper Larsson
//
// This file is part of Klipspringer, <https://klipspringer.avadeaux.net/>
//
// Klipspringer is free software: you can redistribute it and/or modify it under the terms of the
// GNU General Public License as published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// Klipspringer 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 for more details.
//
// You should have received a copy of the GNU General Public License along with Klipspringer. If
// not, see <https://www.gnu.org/licenses/>.

package net.avadeaux.klipspringer.codec;

import java.io.IOException;
import java.nio.ByteBuffer;
import javax.sound.sampled.*;

/** Audio output adapter for writing to a {@link SourceDataLine}. */
public class LinePlayer implements Device.Player {
    private final SourceDataLine line;
    private final PcmFormat format;
    private final ByteTransfer.ArrayWriter lineWriter;

    /** Constructs a player for the given line. Opens the line if not already open, and starts it
      * unless the paused parameter is true.
      */
    public LinePlayer(SourceDataLine line, boolean paused) throws IOException {
        this.line = line;
        this.format = PcmFormat.of(line.getFormat());
        lineWriter = ByteTransfer.ArrayWriter.of(line);
        if (!line.isOpen()) {
            try { line.open(); } catch (LineUnavailableException ex) { throw new IOException(ex); }
        }
        if (!paused) { line.start(); }
    }

    public PcmFormat format() { return format; }

    public Device.BitLayout layout() { return Device.BitLayout.LSB; }

    public boolean write(ByteBuffer data) throws IOException {
        return ByteTransfer.write(data, lineWriter, format.fs());
    }

    public int bufferedFrames() {
        // There seems to be a bug that makes the line sometimes report more available bytes than
        // the buffer size. It has been observed to happen just after the first write. Return 0 in
        // this case, it is at least less wrong than a negative number.
        return Math.max(0, line.getBufferSize() - line.available())/format.fs();
    }

    /** Returns true. */
    public boolean canPause() { return true; }

    public void pause() { line.stop(); }

    public void unpause() { line.start(); }

    public void drain() {
        line.drain();
        close();
    }

    public void close() { line.close(); }
}

Version: v4.3.2.2 (2026-05-16T17:03:34+02:00)
Raw file
Source code overview
Klipspringer home