/* Copyright (c) 2001 Charles Samuels Copyright (c) 2002-2004 Denis Rojo this pipe class was first written by Charles Samuels and almost completely rewritten by Denis "jaromil" Rojo This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. $Id: pipe.h 726 2005-11-07 22:10:35Z xant $ */ /** @file pipe.h @brief Buffered and threadsafe FIFO pipe */ #ifndef __PIPE_H__ #define __PIPE_H__ #include #include #include /** This class defines the implementation of the FIFO (first in, first out) buffered threadsafe pipe. This component is massively used in MuSE's flow of audio data, connecting the Channel to the Stream_mixer and then to the OutChannel. This Pipe implementation is fairly well tested and optimized, usesu pthread mutexes for fast atomical locking and has a mixing routine embedded for for reading data from the pipe. When an application locks the Pipe, will be waiting until it reaches to gain the lock, then will (pthread_mutex_lock) This pipe is never blocking, meaning that it never makes the calling process wait for result. The Pipe::blocking attribute of this class has to be intended in a different way. Blocking means that the Pipe::read, Pipe::write and derivative functions will be returning -1 without moving any data, in case the aumount of data requested don't fit for pipe buffers. Non-blocking means that the Pipe::read, Pipe::write and derivative functions will move all the data they can move, even if less than requested, and then return the amount of data moved. I know, the above might sound weird, just because i used the word 'blocking' where i shouldn't. i beg your pardon and plan to change it in future. @brief fast buffered threadsafe FIFO pipe */ /** this function prototype is used in the callbacks that are handling the phisical copying of the memory. they are various functions statically implemented in pipe.cpp */ typedef void (pipe_copy_f)(void *src, void *dst, int samples); /** this is the prototype struct holding the list of available types */ typedef struct pipe_copy_list { char *name; pipe_copy_f *callback; int src_samplesize; int dst_samplesize; }; class Pipe { public: /** The constructor initializes all buffers needed, which will be in fact the size of the buffer */ Pipe(int size=16384); ///< Pipe constructor class ~Pipe(); ///< Pipe destructor class /** A Pipe can be of different types, meaning that it does different kind of operations when reading or writing like: conversions, mixing of various kinds, all opearations that we can optimize when doing in one single pass, while data is flowing around. Implementations of the various types available can be obtained looking into pipe.cpp when the copy callback functions are registered. The set_input_type and set_output_type methods are used to set which kind of operation the Pipe will execute when moving in and out the data. Default is "copy_byte" which simply copies one byte each sample, you want to change this to set it to the sample type you are using types available: * copy_byte * copy_int16_to_float int to float using /32768.0f * copy_float_to_int16 float to int using lrintf() * mix_int16_to_int32 simple sum of 16bit over 32bit int */ bool set_input_type(char *name); ///< set the input conversion type for this Pipe bool set_output_type(char *name); ///< set the output conversion type for this Pipe void set_block(bool input, bool output); ///< set the blocking policy on the read and write void set_block_timeout(int input, int output); ///< set the timeout in milliseconds for the read and write block /** Reads out audio data from the pipe filling up the given buffer which has to be properly allocated. If the pipe is set 'blocking' then will return -1 if the pipe buffer is full. Otherwise, when non-blocking, will return the amount of data that could be pushed in the pipe. @brief FIFO read from pipe @param length amount of data to be read in bytes @param data buffer pointer where to read data, must be allocated allready @return amount of data read, or -1 on error, if Pipe::blocking is true */ int read(int length, void *data); ///< read from the pipe /** This function is used to read from the pipe directly into a stereo interpolated float audio buffer, which is the ideal input for the secret rabbit code resampler. @brief read from FIFO pipe in a float stereo interpolated l/r array @param samples amount of data to be read in samples (1= l&r float) @param buf float buffer to be filled, must be allocated allready @param channels number of channels (1=mono, 2=stereo) @return amount of data read, or -1 on error, if Pipe::blocking is true */ // int read_float_intl(int samples, float *buf, int channels); /** Read from FIFO pipe in a float bidimensional array. It is convenient to read float data for float routines, this one reads into a bidimensional buffer. TAKE CARE THIS FUNCTION IS NOT WELL TESTED i never use it in MuSE i just did it together with the _intl */ // int read_float_bidi(int samples, float **buf, int channels); ///< read from the pipe into a bidimensional float array /** Mixes the audio in the pipe into a given audio buffer. Assumes that the audio buffered is 16bit stereo. This implements the core mixing routine used in Stream_mixer::cafudda. @brief Mix audio from FIFO pipe into a mixing buffer @param samples number of samples to be mixed (1= l&r 16bit) @param mix 32bit integer mixing buffer @return amount of samples mixed */ // int mix16stereo(int samples, int32_t *mix); // int peek(int length, void *data, bool block=true) const; // TODO /** Write data inside the FIFO pipe, locking to not overlap read operations (thread safe). @brief write into FIFO pipe @param length amount of bytes of data to be written @param data buffer from where to take the data to be written @return when Pipe::blocking is set, this functions returns -1, otherwise the amount of data written. */ int write(int length, void *data); /** Thread safe write data inside the FIFO pipe, like the main write(). In one pass does a conversion over the data being written, from @param length amount of bytes of data to be written @param data buffer from where to take the float data to be converted and written @return the amount of data written */ // int write_float2int(int length, void *data); /** Thread safe write data inside the FIFO pipe, like the main write(). In one pass does a conversion over the data being written, from int to float using casting. @param length amount of bytes of data to be written @param data buffer from where to take the int data to be converted and written @return the amount of data written */ // int write_int2float(int length, void *data); /** @brief Setup blocking behaviour of the Pipe. The term 'blocking' here is used in a quite improper way, read more about in the description of the Pipe class. */ void block(bool val); bool blocking; /** @brief tell the amount of data contained in the Pipe @return amount in bytes */ int size(); /** @brief tell the amount of free space in the Pipe @return amount in bytes */ int space(); void flush(); ///< flush all data contained in the Pipe, loosing it void flush(int size); ///< flush a certain amount of bytes from FIFO Pipe private: pthread_mutex_t _mutex; void _thread_init() { pthread_mutex_init (&_mutex,NULL); }; void _thread_destroy() { pthread_mutex_destroy(&_mutex); }; void lock() { pthread_mutex_lock(&_mutex); }; void unlock() { pthread_mutex_unlock(&_mutex); }; void *buffer; void *bufferEnd; void *start; void *end; pipe_copy_list *read_copy_cb; pipe_copy_list *write_copy_cb; int pipesize; bool read_blocking; bool write_blocking; int read_blocking_time; int write_blocking_time; }; #endif