module iota.audio.output;

import iota.audio.types;
import core.thread;

/** 
 * Defines an output stream for audio output.
 * Periodically calls a callback function (delegate) as long as the stream isn't shut down.
 */
public abstract class OutputStream {
	/** 
	 * The ID of the audio thread if there's any.
	 */
	protected ThreadID _threadID;
	/// The last error code that was encountered, or 0 if none.
	public int			errCode;
	/// Internal state flags.
	protected uint		statusCode;
	public enum StatusFlags {
		IsRunning			=	1<<0,	///Set if thread is running.
		BufferOverrun		=	1<<8,	///Set if a buffer overrun event have happened.
		BufferUnderrun		=	1<<9,	///Set if a buffer underrun event have happened.
	}
	/** 
	 * Returns the thread ID of the stream thread.
	 * Warning: It is not advised to join this thread.
	 */
	public @property ThreadID threadID() @nogc @safe pure nothrow const {
		return _threadID;
	}
	/** 
	 * Called periodically request more data to device output.
	 * Target must not call any functions that either suspend the thread, or would impact real-time performance (disk
	 * operations, etc).
	 */ 
	public @nogc nothrow void delegate(ubyte[] buffer) callback_buffer;
	/** 
	 * Called when a buffer underflow error have occured. (Optional)
	 */
	public @nogc nothrow void delegate() callback_onBufferUnderflow;
	/** 
	 * Runs the audio thread. This either means that it'll create a new low-level thread to feed the stream a steady 
	 * amount of data, or use whatever the backend on the OS has.
	 * Returns: 0, or an error code if there was a failure.
	 */
	public abstract int runAudioThread() @nogc nothrow;
	/**
	 * Suspends the audio thread by allowing it to escape normally and close things safely, or suspending it on the
	 * backend.
	 * Returns: 0, or an error code if there was a failure.
	 * Note: It's wise to put this function into a mutex, or a `synchronized` block.
	 */
	public abstract int suspendAudioThread() @nogc nothrow;
}