You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
6.1 KiB
237 lines
6.1 KiB
/*
|
|
|
|
Copyright (C) 2000 Stefan Westerfeld
|
|
stefan@space.twc.de
|
|
|
|
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., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#ifndef AUDIOSUBSYS_H
|
|
#define AUDIOSUBSYS_H
|
|
#include <string>
|
|
|
|
#include "arts_export.h"
|
|
#include "pipebuffer.h"
|
|
#include "startupmanager.h"
|
|
|
|
/*
|
|
* BC - tqStatus (2002-03-08): AudioSubSystem, ASProducer, ASConsumer.
|
|
*
|
|
* These classes are kept binary compatible. You can rely on them.
|
|
* AudioSubSystem has a private data pointer to do so. Even if ports to
|
|
* other architectures or hardware will require different organization
|
|
* (i.e. no fragments, direct memory access via mmap), the data members
|
|
* and functions exported here MAY NOT BE CHANGED. Use the private data
|
|
* pointer for adding data members.
|
|
*
|
|
* If ASProducer/ASConsumer doesn't suit the needs any longer, do NOT
|
|
* change them. Add new classes instead.
|
|
*/
|
|
|
|
namespace Arts {
|
|
|
|
class ASProducer {
|
|
public:
|
|
virtual void needMore() = 0;
|
|
};
|
|
|
|
// FIXME: haveMore won't be called currently
|
|
class ASConsumer {
|
|
public:
|
|
virtual void haveMore() = 0;
|
|
};
|
|
|
|
class ARTS_EXPORT AudioSubSystemStart :public StartupClass {
|
|
protected:
|
|
class AudioSubSystem *_instance;
|
|
public:
|
|
inline AudioSubSystem *the() { return _instance; };
|
|
void startup();
|
|
void shutdown();
|
|
};
|
|
|
|
class AudioSubSystemPrivate;
|
|
|
|
class ARTS_EXPORT AudioSubSystem {
|
|
class AudioSubSystemPrivate *d;
|
|
|
|
std::string _error;
|
|
char *fragment_buffer;
|
|
|
|
int _fragmentCount;
|
|
int _fragmentSize;
|
|
|
|
bool _running;
|
|
PipeBuffer wBuffer, rBuffer;
|
|
ASConsumer *consumer;
|
|
ASProducer *producer;
|
|
|
|
friend class AudioSubSystemStart;
|
|
AudioSubSystem();
|
|
~AudioSubSystem();
|
|
|
|
void close();
|
|
void initAudioIO();
|
|
|
|
/**
|
|
* checks that full duplex doesn't go out of sync
|
|
*/
|
|
void adjustDuplexBuffers();
|
|
|
|
/**
|
|
* creates count empty fragments of input in rBuffer if count > 0
|
|
* removes count fragments of input from rBuffer if count < 0
|
|
*/
|
|
void adjustInputBuffer(int count);
|
|
|
|
public:
|
|
enum { ioRead=1, ioWrite=2, ioExcept=4 };
|
|
|
|
// singleton
|
|
static AudioSubSystem *the();
|
|
|
|
/*
|
|
* Currently, if you want to use the AudioSubSystem, you need to
|
|
*
|
|
* 1. - attach one producer
|
|
* - attach one consumer (only for full duplex)
|
|
* - open the audio subsystem using open (watch the fd)
|
|
* (in any order)
|
|
*
|
|
* 2. react on the callbacks you get for the producer
|
|
*
|
|
* 3. if you don't need the audio subsystem any longer, call detach
|
|
* both, the producer and the cosumer.
|
|
*
|
|
* Be careful that you don't read/write from/to the audio subsystem
|
|
* when running() is not true.
|
|
*/
|
|
|
|
bool attachProducer(ASProducer *producer);
|
|
bool attachConsumer(ASConsumer *consumer);
|
|
|
|
void detachProducer();
|
|
void detachConsumer();
|
|
|
|
/*
|
|
* can be used to select the AudioIO class to use, reasonable choices
|
|
* may be "oss" or "alsa" at this point in time - you need to choose
|
|
* this before doing anything else
|
|
*/
|
|
void audioIO(const std::string& audioIO);
|
|
std::string audioIO();
|
|
|
|
// which device to use for audio output (default /dev/dsp)
|
|
void deviceName(const std::string& deviceName);
|
|
std::string deviceName();
|
|
|
|
void fragmentSize(int size);
|
|
int fragmentSize();
|
|
|
|
void fragmentCount(int fragments);
|
|
int fragmentCount();
|
|
|
|
void samplingRate(int samplingrate);
|
|
int samplingRate();
|
|
|
|
void channels(int channels);
|
|
int channels();
|
|
|
|
void format(int format);
|
|
int format();
|
|
|
|
/**
|
|
* As opposed to format(), this one returns the number of bits used per
|
|
* sample. Thats sometimes a difference, for instance 16bit big endian
|
|
* encoding has the format() 17, whereas bits() would return 16.
|
|
*/
|
|
int bits();
|
|
|
|
void fullDuplex(bool newFullDuplex);
|
|
bool fullDuplex();
|
|
|
|
bool check();
|
|
|
|
/**
|
|
* Opens the audio device.
|
|
*
|
|
* After opening, you must check selectReadFD() and selectWriteFD() to
|
|
* select() on the appropriate file descriptors. Whenever select()ing is
|
|
* successful, handleIO needs to be called.
|
|
*
|
|
* The type for handleIO must be set to ioRead if fd is ready for
|
|
* reading, ioWrite if fd is ready for writing, ioExcept if something
|
|
* special happend or any combination of these using bitwise or.
|
|
*
|
|
* @returns true if audio device has been opened successfully,
|
|
* false otherwise
|
|
*/
|
|
bool open();
|
|
|
|
/**
|
|
* human readable error message that descibes why opening the audio device
|
|
* failed
|
|
*/
|
|
const char *error();
|
|
|
|
/**
|
|
* File descriptor to select on for reading (@see open()), -1 if there is
|
|
* none.
|
|
*/
|
|
int selectReadFD();
|
|
|
|
/**
|
|
* File descriptor to select on for writing (@see open()), -1 if there is
|
|
* none.
|
|
*/
|
|
int selectWriteFD();
|
|
|
|
/**
|
|
* Needs to be called to handle I/O on the filedescriptors given by
|
|
* selectReadFD() and selectWriteFD() (@see open()).
|
|
*/
|
|
void handleIO(int type);
|
|
|
|
void read(void *buffer, int size);
|
|
void write(void *buffer, int size);
|
|
|
|
/**
|
|
* this returns the time in seconds it will take until everything written
|
|
* to the AudioSubSystem so far will be played - in other words, it returns
|
|
* the time it will take until the next sample written by the application
|
|
* will be heard by the user
|
|
*/
|
|
float outputDelay();
|
|
|
|
/**
|
|
* returns true as long as the audio subsystem is opened and active (that
|
|
* is, between successful opening, with attaching producer, and the first
|
|
* detachConsumer/detachProducer)
|
|
*/
|
|
bool running();
|
|
|
|
/**
|
|
* called during crashes, to release the opened device (and other resources)
|
|
* don't use this method for other purposes than emergencies
|
|
*/
|
|
void emergencyCleanup();
|
|
};
|
|
|
|
}
|
|
|
|
#endif /* AUDIOSUBSYS_H */
|