From 00d4f92b717fbcbed6f9eee361975d6ee5380d59 Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Sun, 6 Dec 2020 19:28:06 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro --- artsc/CMakeLists.txt | 2 +- artsc/artscbackend.cc | 805 ------------------------------------------------- artsc/artscbackend.cpp | 805 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 806 insertions(+), 806 deletions(-) delete mode 100644 artsc/artscbackend.cc create mode 100644 artsc/artscbackend.cpp (limited to 'artsc') diff --git a/artsc/CMakeLists.txt b/artsc/CMakeLists.txt index 6a5955e..0966a45 100644 --- a/artsc/CMakeLists.txt +++ b/artsc/CMakeLists.txt @@ -104,7 +104,7 @@ set_property( TARGET artsc-shared APPEND PROPERTY COMPILE_DEFINITIONS ARTSC_BACK ##### artscbackend (shared lib) ################# tde_add_library( artscbackend SHARED - SOURCES artscbackend.cc + SOURCES artscbackend.cpp VERSION 0.0.0 LINK soundserver_idl-shared artsflow-shared DESTINATION ${LIB_INSTALL_DIR} diff --git a/artsc/artscbackend.cc b/artsc/artscbackend.cc deleted file mode 100644 index 56d0868..0000000 --- a/artsc/artscbackend.cc +++ /dev/null @@ -1,805 +0,0 @@ - /* - - Copyright (C) 2000 Stefan Westerfeld - stefan@space.twc.de - 2001 Matthias Kretz - kretz@kde.org - - 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. - - */ - -#include "artsc.h" -#include "soundserver.h" -#include "stdsynthmodule.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "arts_export.h" - -#define arts_backend_debug(x) ; - -using namespace std; -using namespace Arts; - -/** - * Base class for streams - */ -class Stream -{ -protected: - SoundServer server; - float serverBufferTime; - - bool _finished, isAttached; - int _samplingRate, _bits, _channels, pos; - string _name; - queue< DataPacket* > streamqueue; - - int packetCount, packetCapacity; - int blockingIO; - - /** - * returns the amount of bytes that will be played in a given amount of - * time in milliseconds - */ - int timeToBytes(float time) - { - float playSpeed = _channels * _samplingRate * _bits / 8; - return (int)(playSpeed * (time / 1000.0)); - } - - /** - * returns the time in milliseconds it takes with the current parameters - * to play a given amount of bytes - */ - float bytesToTime(int size) - { - float playSpeed = _channels * _samplingRate * _bits / 8; - return (1000.0 * ((float)size) / playSpeed); - } - - int bufferSize() { - return packetCount * packetCapacity; - } - - float bufferTime() { - return bytesToTime(bufferSize()); - } - - int bufferSpace() { - int space = 0; - - attach(); - - /* make sure that our information is up-to-date */ - Dispatcher::the()->ioManager()->processOneEvent(false); - - if(!streamqueue.empty()) - { - space += packetCapacity - pos; /* the first, half filled packet */ - - if(streamqueue.size() > 1) /* and the other, empty packets */ - space += (streamqueue.size()-1)*packetCapacity; - } - return space; - } - - int setBufferSize(int size) - { - /* don't change sizes when already streaming */ - if(isAttached) - return ARTS_E_NOIMPL; - - /* - * these parameters are usually a bad idea ;-) however we have to start - * somewhere, and maybe in two years, with a highly optimized kernel - * this is possible - for now, don't request the impossible or don't - * complain if it doesn't work - */ - packetCount = 3; - packetCapacity = 128; - - /* - * - do not configure stream buffers smaller than the server - * recommended value - * - try to get more or less close to the value the application - * wants - */ - int needSize = max(size, timeToBytes(server.minStreamBufferTime())); - - while(bufferSize() < needSize) - { - packetCount++; - if(packetCount == 8) - { - packetCount /= 2; - packetCapacity *= 2; - } - } - - return bufferSize(); - } - - int packetSettings() - { - int settings = 0; - - int cap = packetCapacity; - while(cap > 1) - { - settings++; - cap /= 2; - } - - settings |= packetCount << 16; - return settings; - } - - int setPacketSettings(int settings) - { - /* don't change sizes when already streaming */ - if(isAttached) - return ARTS_E_NOIMPL; - - packetCount = settings >> 16; - - packetCapacity = 1; - int c = settings & 0xffff; - while(c > 0) { - packetCapacity *= 2; - c--; - } - - /* - * - do not configure stream buffers smaller than the server - * recommended value - * - keep the packetSize the applications specified - */ - int needSize = timeToBytes(server.minStreamBufferTime()); - - while(bufferSize() < needSize) - packetCount++; - - return packetSettings(); - } - - /** - * the stream has to attach itself - */ - virtual void attach() = 0; - -public: - Stream(SoundServer server, int rate, int bits, int channels, - string name) : server(server), _finished(false), isAttached(false), - _samplingRate(rate), _bits(bits), _channels(channels), pos(0), - _name(name) - { - serverBufferTime = server.serverBufferTime(); - stream_set(ARTS_P_BUFFER_SIZE,64*1024); - stream_set(ARTS_P_BLOCKING,1); - } - virtual ~Stream() - { - // - } - - virtual int stream_set(arts_parameter_t param, int value) - { - int result; - - switch(param) { - case ARTS_P_BUFFER_SIZE: - return setBufferSize(value); - - case ARTS_P_BUFFER_TIME: - result = setBufferSize(timeToBytes(value)); - if(result < 0) return result; - return (int)bufferTime(); - - case ARTS_P_PACKET_SETTINGS: - return setPacketSettings(value); - - case ARTS_P_BLOCKING: - if(value != 0 && value != 1) return ARTS_E_NOIMPL; - - blockingIO = value; - return blockingIO; - /* - * maybe ARTS_P_TOTAL_LATENCY _could_ be made writeable, the - * others are of course useless - */ - case ARTS_P_BUFFER_SPACE: - case ARTS_P_SERVER_LATENCY: - case ARTS_P_TOTAL_LATENCY: - case ARTS_P_PACKET_SIZE: - case ARTS_P_PACKET_COUNT: - return ARTS_E_NOIMPL; - } - return ARTS_E_NOIMPL; - } - - virtual int stream_get(arts_parameter_t param) - { - switch(param) { - case ARTS_P_BUFFER_SIZE: - return bufferSize(); - - case ARTS_P_BUFFER_TIME: - return (int)bufferTime(); - - case ARTS_P_BUFFER_SPACE: - return bufferSpace(); - - case ARTS_P_PACKET_SETTINGS: - return packetSettings(); - - case ARTS_P_SERVER_LATENCY: - return (int)serverBufferTime; - - case ARTS_P_TOTAL_LATENCY: - return stream_get(ARTS_P_SERVER_LATENCY) - + stream_get(ARTS_P_BUFFER_TIME); - - case ARTS_P_BLOCKING: - return blockingIO; - - case ARTS_P_PACKET_SIZE: - return packetCapacity; - - case ARTS_P_PACKET_COUNT: - return packetCount; - } - return ARTS_E_NOIMPL; - } - - virtual int write(const mcopbyte * /*data*/, int /*size*/) - { - return ARTS_E_NOIMPL; - } - - virtual int read(mcopbyte * /*data*/, int /*size*/) - { - return ARTS_E_NOIMPL; - } - - virtual void close() = 0; - - int suspend() - { - if(isAttached) - { - return server.suspend(); - } - return 0; - } - - int suspended() - { - if(isAttached) - { - return 0; - } - return server.suspended(); - } -}; - -class Receiver : public ByteSoundReceiver_skel, - public StdSynthModule, - virtual public Stream -{ - /* - * FIXME: bsWrapper is a more or less ugly trick to be able to use - * this object although not using smartwrappers to access it - */ - ByteSoundReceiver bsWrapper; - -protected: - virtual void attach() - { - if(!isAttached) - { - isAttached = true; - - server.attachRecorder(bsWrapper); - start(); - - /* - * TODO: this processOneEvent looks a bit strange here... it is - * there since StdIOManager does block 5 seconds on the first - * arts_write if it isn't - although notifications are pending - * - * Probably the real solution is to rewrite the - * StdIOManager::processOneEvent function. (And maybe drop the - * assumption that aRts will not block when an infinite amount - * of notifications is pending - I mean: will it ever happen?) - */ - Dispatcher::the()->ioManager()->processOneEvent(false); - } - } - -public: - Receiver(SoundServer server, int rate, int bits, int channels, - string name) : Stream( server, rate, bits, channels, name) - { - bsWrapper = ByteSoundReceiver::_from_base(this); - } - - virtual ~Receiver() { - // - } - - long samplingRate() { return _samplingRate; } - long channels() { return _channels; } - long bits() { return _bits; } - bool finished() { return _finished; } - string title() { return _name; } - - void process_indata(DataPacket *packet) - { - streamqueue.push(packet); - } - - void close() - { - if(isAttached) - { - /* remove all packets from the streamqueue */ - while(!streamqueue.empty()) - { - DataPacket *packet = streamqueue.front(); - packet->processed(); - streamqueue.pop(); - } - - server.detachRecorder(bsWrapper); - } - // similar effect like "delete this;" - bsWrapper = ByteSoundReceiver::null(); - } - - int read(mcopbyte *data, int size) - { - attach(); - - int remaining = size; - while(remaining) - { - if(blockingIO) - { - /* C API blocking style read */ - while(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(true); - } - else - { - /* non blocking I/O */ - if(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(false); - - /* still no more packets to read? */ - if(streamqueue.empty()) - return size - remaining; - } - - /* get a packet */ - DataPacket *packet = streamqueue.front(); - - /* copy some data from there */ - int tocopy = min(remaining,packet->size-pos); - memcpy(data,&packet->contents[pos],tocopy); - pos += tocopy; - data += tocopy; - remaining -= tocopy; - - /* have we read the whole packet? then get rid of it */ - if(pos == packet->size) - { - packet->processed(); - streamqueue.pop(); - pos = 0; - } - } - - /* no possible error conditions */ - return size; - } -}; - -class Sender : public ByteSoundProducerV2_skel, - public StdSynthModule, - virtual public Stream -{ - /* - * FIXME: bsWrapper is a more or less ugly trick to be able to use - * this object although not using smartwrappers to access it - */ - ByteSoundProducerV2 bsWrapper; - -protected: - virtual void attach() - { - if(!isAttached) - { - isAttached = true; - - server.attach(bsWrapper); - start(); - - /* - * TODO: this processOneEvent looks a bit strange here... it is - * there since StdIOManager does block 5 seconds on the first - * arts_write if it isn't - although notifications are pending - * - * Probably the real solution is to rewrite the - * StdIOManager::processOneEvent function. (And maybe drop the - * assumption that aRts will not block when an infinite amount - * of notifications is pending - I mean: will it ever happen?) - */ - Dispatcher::the()->ioManager()->processOneEvent(false); - } - } - -public: - Sender(SoundServer server, int rate, int bits, int channels, - string name) : Stream( server, rate, bits, channels, name) - { - bsWrapper = ByteSoundProducerV2::_from_base(this); - } - - virtual ~Sender() { - // - } - - long samplingRate() { return _samplingRate; } - long channels() { return _channels; } - long bits() { return _bits; } - bool finished() { return _finished; } - string title() { return _name; } - - void streamStart() - { - /* - * start streaming - */ - outdata.setPull(packetCount, packetCapacity); - } - - void request_outdata(DataPacket *packet) - { - streamqueue.push(packet); - } - - void close() - { - if(isAttached) - { - if(pos != 0) - { - /* send the last half-filled packet */ - DataPacket *packet = streamqueue.front(); - packet->size = pos; - packet->send(); - streamqueue.pop(); - } - outdata.endPull(); - - /* remove all packets from the streamqueue */ - while(!streamqueue.empty()) - { - DataPacket *packet = streamqueue.front(); - packet->size = 0; - packet->send(); - streamqueue.pop(); - } - - server.detach(bsWrapper); - } - // similar effect like "delete this;" - Arts::ByteSoundProducerV2_base* x = _copy(); - bsWrapper = ByteSoundProducerV2::null(); - x->_release(); - } - - int write(const mcopbyte *data, int size) - { - attach(); - - int remaining = size; - while(remaining) - { - if(blockingIO) - { - /* C API blocking style write */ - /* we're not waiting for any data here, but rather for - * DataPackets that we can fill */ - while(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(true); - } - else - { - /* non blocking I/O */ - if(streamqueue.empty()) - Dispatcher::the()->ioManager()->processOneEvent(false); - - /* still no more space to write? */ - if(streamqueue.empty()) - return size - remaining; - } - - /* get a packet */ - DataPacket *packet = streamqueue.front(); - - /* copy some data there */ - int tocopy = min(remaining,packetCapacity-pos); - memcpy(&packet->contents[pos],data,tocopy); - pos += tocopy; - data += tocopy; - remaining -= tocopy; - - /* have we filled up the packet? then send it */ - if(pos == packetCapacity) - { - packet->size = packetCapacity; - packet->send(); - streamqueue.pop(); - pos = 0; - } - } - - /* no possible error conditions */ - return size; - } -}; - -class ArtsCApi { -protected: - static ArtsCApi *instance; - int refcnt; - - Dispatcher dispatcher; - SoundServer server; - - ArtsCApi() : refcnt(1), server(Reference("global:Arts_SoundServer")) - { - // - } - -public: -// C Api commands - int init() { - if(server.isNull()) - return ARTS_E_NOSERVER; - - return 0; - } - - int suspend() { - if(!server.isNull()) - return server.suspend()? 1:0; - return ARTS_E_NOSERVER; - } - - int suspended() { - if(!server.isNull()) - return server.suspended()? 1:0; - return ARTS_E_NOSERVER; - } - - void free() { - // nothing to do - } - - arts_stream_t play_stream(int rate, int bits, int channels, const char *name) - { - if(server.isNull()) - return 0; - - return (arts_stream_t)static_cast(new Sender(server,rate,bits,channels,name)); - } - - arts_stream_t record_stream(int rate, int bits, int channels, const char *name) - { - if(server.isNull()) - return 0; - - return (arts_stream_t)static_cast(new Receiver(server,rate,bits,channels,name)); - } - - void close_stream(arts_stream_t stream) - { - if(server.isNull()) - return; - - if(!stream) - return; - - static_cast(stream)->close(); - } - - int write(arts_stream_t stream, const void *data, int size) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->write((const mcopbyte *)data,size); - } - - int read(arts_stream_t stream, void *data, int size) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->read((mcopbyte *)data,size); - } - - int stream_set(arts_stream_t stream, arts_parameter_t param, int value) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->stream_set(param,value); - } - - int stream_get(arts_stream_t stream, arts_parameter_t param) - { - if(server.isNull()) - return ARTS_E_NOSERVER; - - if(!stream) - return ARTS_E_NOSTREAM; - - return static_cast(stream)->stream_get(param); - } - -// allocation and freeing of the class - static ArtsCApi *the() { - return instance; - } - static void ref() { - if(!instance) - instance = new ArtsCApi(); - else - instance->refcnt++; - } - static void release() { - assert(instance); - assert(instance->refcnt > 0); - instance->refcnt--; - if(instance->refcnt == 0) - { - delete instance; - instance = 0; - } - } -}; - -//----------------------------- static members ------------------------------- - -ArtsCApi *ArtsCApi::instance = 0; - -//------------------ wrappers from C to C++ class ---------------------------- - -extern "C" ARTSC_EXPORT int arts_backend_init() -{ - arts_backend_debug("arts_backend_init"); - ArtsCApi::ref(); - - // if init fails, don't expect free, and don't expect that the user - // continues using other API functions - int rc = ArtsCApi::the()->init(); - if(rc < 0) ArtsCApi::release(); - return rc; -} - -extern "C" ARTSC_EXPORT int arts_backend_suspend() -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - arts_backend_debug("arts_backend_suspend"); - return ArtsCApi::the()->suspend(); -} - -extern "C" ARTSC_EXPORT int arts_backend_suspended() -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - arts_backend_debug("arts_backend_suspended"); - return ArtsCApi::the()->suspended(); -} - -extern "C" ARTSC_EXPORT void arts_backend_free() -{ - if(!ArtsCApi::the()) return; - - arts_backend_debug("arts_backend_free"); - ArtsCApi::the()->free(); - ArtsCApi::release(); -} - -extern "C" ARTSC_EXPORT arts_stream_t arts_backend_play_stream(int rate, int bits, int channels, const char *name) -{ - if(!ArtsCApi::the()) return 0; - - arts_backend_debug("arts_backend_play_stream"); - return ArtsCApi::the()->play_stream(rate,bits,channels,name); -} - -extern "C" ARTSC_EXPORT arts_stream_t arts_backend_record_stream(int rate, int bits, int channels, const char *name) -{ - if(!ArtsCApi::the()) return 0; - - arts_backend_debug("arts_backend_record_stream"); - return ArtsCApi::the()->record_stream(rate,bits,channels,name); -} - -extern "C" ARTSC_EXPORT void arts_backend_close_stream(arts_stream_t stream) -{ - if(!ArtsCApi::the()) return; - - arts_backend_debug("arts_backend_close_stream"); - ArtsCApi::the()->close_stream(stream); -} - -extern "C" ARTSC_EXPORT int arts_backend_read(arts_stream_t stream, void *buffer, int count) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_backend_read"); - return ArtsCApi::the()->read(stream,buffer,count); -} - -extern "C" ARTSC_EXPORT int arts_backend_write(arts_stream_t stream, const void *buffer, - int count) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_backend_write"); - return ArtsCApi::the()->write(stream,buffer,count); -} - -extern "C" ARTSC_EXPORT int arts_backend_stream_set(arts_stream_t stream, - arts_parameter_t param, int value) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_stream_set"); - return ArtsCApi::the()->stream_set(stream,param,value); -} - -extern "C" ARTSC_EXPORT int arts_backend_stream_get(arts_stream_t stream, - arts_parameter_t param) -{ - if(!ArtsCApi::the()) return ARTS_E_NOINIT; - - arts_backend_debug("arts_stream_get"); - return ArtsCApi::the()->stream_get(stream,param); -} diff --git a/artsc/artscbackend.cpp b/artsc/artscbackend.cpp new file mode 100644 index 0000000..56d0868 --- /dev/null +++ b/artsc/artscbackend.cpp @@ -0,0 +1,805 @@ + /* + + Copyright (C) 2000 Stefan Westerfeld + stefan@space.twc.de + 2001 Matthias Kretz + kretz@kde.org + + 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. + + */ + +#include "artsc.h" +#include "soundserver.h" +#include "stdsynthmodule.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "arts_export.h" + +#define arts_backend_debug(x) ; + +using namespace std; +using namespace Arts; + +/** + * Base class for streams + */ +class Stream +{ +protected: + SoundServer server; + float serverBufferTime; + + bool _finished, isAttached; + int _samplingRate, _bits, _channels, pos; + string _name; + queue< DataPacket* > streamqueue; + + int packetCount, packetCapacity; + int blockingIO; + + /** + * returns the amount of bytes that will be played in a given amount of + * time in milliseconds + */ + int timeToBytes(float time) + { + float playSpeed = _channels * _samplingRate * _bits / 8; + return (int)(playSpeed * (time / 1000.0)); + } + + /** + * returns the time in milliseconds it takes with the current parameters + * to play a given amount of bytes + */ + float bytesToTime(int size) + { + float playSpeed = _channels * _samplingRate * _bits / 8; + return (1000.0 * ((float)size) / playSpeed); + } + + int bufferSize() { + return packetCount * packetCapacity; + } + + float bufferTime() { + return bytesToTime(bufferSize()); + } + + int bufferSpace() { + int space = 0; + + attach(); + + /* make sure that our information is up-to-date */ + Dispatcher::the()->ioManager()->processOneEvent(false); + + if(!streamqueue.empty()) + { + space += packetCapacity - pos; /* the first, half filled packet */ + + if(streamqueue.size() > 1) /* and the other, empty packets */ + space += (streamqueue.size()-1)*packetCapacity; + } + return space; + } + + int setBufferSize(int size) + { + /* don't change sizes when already streaming */ + if(isAttached) + return ARTS_E_NOIMPL; + + /* + * these parameters are usually a bad idea ;-) however we have to start + * somewhere, and maybe in two years, with a highly optimized kernel + * this is possible - for now, don't request the impossible or don't + * complain if it doesn't work + */ + packetCount = 3; + packetCapacity = 128; + + /* + * - do not configure stream buffers smaller than the server + * recommended value + * - try to get more or less close to the value the application + * wants + */ + int needSize = max(size, timeToBytes(server.minStreamBufferTime())); + + while(bufferSize() < needSize) + { + packetCount++; + if(packetCount == 8) + { + packetCount /= 2; + packetCapacity *= 2; + } + } + + return bufferSize(); + } + + int packetSettings() + { + int settings = 0; + + int cap = packetCapacity; + while(cap > 1) + { + settings++; + cap /= 2; + } + + settings |= packetCount << 16; + return settings; + } + + int setPacketSettings(int settings) + { + /* don't change sizes when already streaming */ + if(isAttached) + return ARTS_E_NOIMPL; + + packetCount = settings >> 16; + + packetCapacity = 1; + int c = settings & 0xffff; + while(c > 0) { + packetCapacity *= 2; + c--; + } + + /* + * - do not configure stream buffers smaller than the server + * recommended value + * - keep the packetSize the applications specified + */ + int needSize = timeToBytes(server.minStreamBufferTime()); + + while(bufferSize() < needSize) + packetCount++; + + return packetSettings(); + } + + /** + * the stream has to attach itself + */ + virtual void attach() = 0; + +public: + Stream(SoundServer server, int rate, int bits, int channels, + string name) : server(server), _finished(false), isAttached(false), + _samplingRate(rate), _bits(bits), _channels(channels), pos(0), + _name(name) + { + serverBufferTime = server.serverBufferTime(); + stream_set(ARTS_P_BUFFER_SIZE,64*1024); + stream_set(ARTS_P_BLOCKING,1); + } + virtual ~Stream() + { + // + } + + virtual int stream_set(arts_parameter_t param, int value) + { + int result; + + switch(param) { + case ARTS_P_BUFFER_SIZE: + return setBufferSize(value); + + case ARTS_P_BUFFER_TIME: + result = setBufferSize(timeToBytes(value)); + if(result < 0) return result; + return (int)bufferTime(); + + case ARTS_P_PACKET_SETTINGS: + return setPacketSettings(value); + + case ARTS_P_BLOCKING: + if(value != 0 && value != 1) return ARTS_E_NOIMPL; + + blockingIO = value; + return blockingIO; + /* + * maybe ARTS_P_TOTAL_LATENCY _could_ be made writeable, the + * others are of course useless + */ + case ARTS_P_BUFFER_SPACE: + case ARTS_P_SERVER_LATENCY: + case ARTS_P_TOTAL_LATENCY: + case ARTS_P_PACKET_SIZE: + case ARTS_P_PACKET_COUNT: + return ARTS_E_NOIMPL; + } + return ARTS_E_NOIMPL; + } + + virtual int stream_get(arts_parameter_t param) + { + switch(param) { + case ARTS_P_BUFFER_SIZE: + return bufferSize(); + + case ARTS_P_BUFFER_TIME: + return (int)bufferTime(); + + case ARTS_P_BUFFER_SPACE: + return bufferSpace(); + + case ARTS_P_PACKET_SETTINGS: + return packetSettings(); + + case ARTS_P_SERVER_LATENCY: + return (int)serverBufferTime; + + case ARTS_P_TOTAL_LATENCY: + return stream_get(ARTS_P_SERVER_LATENCY) + + stream_get(ARTS_P_BUFFER_TIME); + + case ARTS_P_BLOCKING: + return blockingIO; + + case ARTS_P_PACKET_SIZE: + return packetCapacity; + + case ARTS_P_PACKET_COUNT: + return packetCount; + } + return ARTS_E_NOIMPL; + } + + virtual int write(const mcopbyte * /*data*/, int /*size*/) + { + return ARTS_E_NOIMPL; + } + + virtual int read(mcopbyte * /*data*/, int /*size*/) + { + return ARTS_E_NOIMPL; + } + + virtual void close() = 0; + + int suspend() + { + if(isAttached) + { + return server.suspend(); + } + return 0; + } + + int suspended() + { + if(isAttached) + { + return 0; + } + return server.suspended(); + } +}; + +class Receiver : public ByteSoundReceiver_skel, + public StdSynthModule, + virtual public Stream +{ + /* + * FIXME: bsWrapper is a more or less ugly trick to be able to use + * this object although not using smartwrappers to access it + */ + ByteSoundReceiver bsWrapper; + +protected: + virtual void attach() + { + if(!isAttached) + { + isAttached = true; + + server.attachRecorder(bsWrapper); + start(); + + /* + * TODO: this processOneEvent looks a bit strange here... it is + * there since StdIOManager does block 5 seconds on the first + * arts_write if it isn't - although notifications are pending + * + * Probably the real solution is to rewrite the + * StdIOManager::processOneEvent function. (And maybe drop the + * assumption that aRts will not block when an infinite amount + * of notifications is pending - I mean: will it ever happen?) + */ + Dispatcher::the()->ioManager()->processOneEvent(false); + } + } + +public: + Receiver(SoundServer server, int rate, int bits, int channels, + string name) : Stream( server, rate, bits, channels, name) + { + bsWrapper = ByteSoundReceiver::_from_base(this); + } + + virtual ~Receiver() { + // + } + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + bool finished() { return _finished; } + string title() { return _name; } + + void process_indata(DataPacket *packet) + { + streamqueue.push(packet); + } + + void close() + { + if(isAttached) + { + /* remove all packets from the streamqueue */ + while(!streamqueue.empty()) + { + DataPacket *packet = streamqueue.front(); + packet->processed(); + streamqueue.pop(); + } + + server.detachRecorder(bsWrapper); + } + // similar effect like "delete this;" + bsWrapper = ByteSoundReceiver::null(); + } + + int read(mcopbyte *data, int size) + { + attach(); + + int remaining = size; + while(remaining) + { + if(blockingIO) + { + /* C API blocking style read */ + while(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(true); + } + else + { + /* non blocking I/O */ + if(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(false); + + /* still no more packets to read? */ + if(streamqueue.empty()) + return size - remaining; + } + + /* get a packet */ + DataPacket *packet = streamqueue.front(); + + /* copy some data from there */ + int tocopy = min(remaining,packet->size-pos); + memcpy(data,&packet->contents[pos],tocopy); + pos += tocopy; + data += tocopy; + remaining -= tocopy; + + /* have we read the whole packet? then get rid of it */ + if(pos == packet->size) + { + packet->processed(); + streamqueue.pop(); + pos = 0; + } + } + + /* no possible error conditions */ + return size; + } +}; + +class Sender : public ByteSoundProducerV2_skel, + public StdSynthModule, + virtual public Stream +{ + /* + * FIXME: bsWrapper is a more or less ugly trick to be able to use + * this object although not using smartwrappers to access it + */ + ByteSoundProducerV2 bsWrapper; + +protected: + virtual void attach() + { + if(!isAttached) + { + isAttached = true; + + server.attach(bsWrapper); + start(); + + /* + * TODO: this processOneEvent looks a bit strange here... it is + * there since StdIOManager does block 5 seconds on the first + * arts_write if it isn't - although notifications are pending + * + * Probably the real solution is to rewrite the + * StdIOManager::processOneEvent function. (And maybe drop the + * assumption that aRts will not block when an infinite amount + * of notifications is pending - I mean: will it ever happen?) + */ + Dispatcher::the()->ioManager()->processOneEvent(false); + } + } + +public: + Sender(SoundServer server, int rate, int bits, int channels, + string name) : Stream( server, rate, bits, channels, name) + { + bsWrapper = ByteSoundProducerV2::_from_base(this); + } + + virtual ~Sender() { + // + } + + long samplingRate() { return _samplingRate; } + long channels() { return _channels; } + long bits() { return _bits; } + bool finished() { return _finished; } + string title() { return _name; } + + void streamStart() + { + /* + * start streaming + */ + outdata.setPull(packetCount, packetCapacity); + } + + void request_outdata(DataPacket *packet) + { + streamqueue.push(packet); + } + + void close() + { + if(isAttached) + { + if(pos != 0) + { + /* send the last half-filled packet */ + DataPacket *packet = streamqueue.front(); + packet->size = pos; + packet->send(); + streamqueue.pop(); + } + outdata.endPull(); + + /* remove all packets from the streamqueue */ + while(!streamqueue.empty()) + { + DataPacket *packet = streamqueue.front(); + packet->size = 0; + packet->send(); + streamqueue.pop(); + } + + server.detach(bsWrapper); + } + // similar effect like "delete this;" + Arts::ByteSoundProducerV2_base* x = _copy(); + bsWrapper = ByteSoundProducerV2::null(); + x->_release(); + } + + int write(const mcopbyte *data, int size) + { + attach(); + + int remaining = size; + while(remaining) + { + if(blockingIO) + { + /* C API blocking style write */ + /* we're not waiting for any data here, but rather for + * DataPackets that we can fill */ + while(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(true); + } + else + { + /* non blocking I/O */ + if(streamqueue.empty()) + Dispatcher::the()->ioManager()->processOneEvent(false); + + /* still no more space to write? */ + if(streamqueue.empty()) + return size - remaining; + } + + /* get a packet */ + DataPacket *packet = streamqueue.front(); + + /* copy some data there */ + int tocopy = min(remaining,packetCapacity-pos); + memcpy(&packet->contents[pos],data,tocopy); + pos += tocopy; + data += tocopy; + remaining -= tocopy; + + /* have we filled up the packet? then send it */ + if(pos == packetCapacity) + { + packet->size = packetCapacity; + packet->send(); + streamqueue.pop(); + pos = 0; + } + } + + /* no possible error conditions */ + return size; + } +}; + +class ArtsCApi { +protected: + static ArtsCApi *instance; + int refcnt; + + Dispatcher dispatcher; + SoundServer server; + + ArtsCApi() : refcnt(1), server(Reference("global:Arts_SoundServer")) + { + // + } + +public: +// C Api commands + int init() { + if(server.isNull()) + return ARTS_E_NOSERVER; + + return 0; + } + + int suspend() { + if(!server.isNull()) + return server.suspend()? 1:0; + return ARTS_E_NOSERVER; + } + + int suspended() { + if(!server.isNull()) + return server.suspended()? 1:0; + return ARTS_E_NOSERVER; + } + + void free() { + // nothing to do + } + + arts_stream_t play_stream(int rate, int bits, int channels, const char *name) + { + if(server.isNull()) + return 0; + + return (arts_stream_t)static_cast(new Sender(server,rate,bits,channels,name)); + } + + arts_stream_t record_stream(int rate, int bits, int channels, const char *name) + { + if(server.isNull()) + return 0; + + return (arts_stream_t)static_cast(new Receiver(server,rate,bits,channels,name)); + } + + void close_stream(arts_stream_t stream) + { + if(server.isNull()) + return; + + if(!stream) + return; + + static_cast(stream)->close(); + } + + int write(arts_stream_t stream, const void *data, int size) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->write((const mcopbyte *)data,size); + } + + int read(arts_stream_t stream, void *data, int size) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->read((mcopbyte *)data,size); + } + + int stream_set(arts_stream_t stream, arts_parameter_t param, int value) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->stream_set(param,value); + } + + int stream_get(arts_stream_t stream, arts_parameter_t param) + { + if(server.isNull()) + return ARTS_E_NOSERVER; + + if(!stream) + return ARTS_E_NOSTREAM; + + return static_cast(stream)->stream_get(param); + } + +// allocation and freeing of the class + static ArtsCApi *the() { + return instance; + } + static void ref() { + if(!instance) + instance = new ArtsCApi(); + else + instance->refcnt++; + } + static void release() { + assert(instance); + assert(instance->refcnt > 0); + instance->refcnt--; + if(instance->refcnt == 0) + { + delete instance; + instance = 0; + } + } +}; + +//----------------------------- static members ------------------------------- + +ArtsCApi *ArtsCApi::instance = 0; + +//------------------ wrappers from C to C++ class ---------------------------- + +extern "C" ARTSC_EXPORT int arts_backend_init() +{ + arts_backend_debug("arts_backend_init"); + ArtsCApi::ref(); + + // if init fails, don't expect free, and don't expect that the user + // continues using other API functions + int rc = ArtsCApi::the()->init(); + if(rc < 0) ArtsCApi::release(); + return rc; +} + +extern "C" ARTSC_EXPORT int arts_backend_suspend() +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + arts_backend_debug("arts_backend_suspend"); + return ArtsCApi::the()->suspend(); +} + +extern "C" ARTSC_EXPORT int arts_backend_suspended() +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + arts_backend_debug("arts_backend_suspended"); + return ArtsCApi::the()->suspended(); +} + +extern "C" ARTSC_EXPORT void arts_backend_free() +{ + if(!ArtsCApi::the()) return; + + arts_backend_debug("arts_backend_free"); + ArtsCApi::the()->free(); + ArtsCApi::release(); +} + +extern "C" ARTSC_EXPORT arts_stream_t arts_backend_play_stream(int rate, int bits, int channels, const char *name) +{ + if(!ArtsCApi::the()) return 0; + + arts_backend_debug("arts_backend_play_stream"); + return ArtsCApi::the()->play_stream(rate,bits,channels,name); +} + +extern "C" ARTSC_EXPORT arts_stream_t arts_backend_record_stream(int rate, int bits, int channels, const char *name) +{ + if(!ArtsCApi::the()) return 0; + + arts_backend_debug("arts_backend_record_stream"); + return ArtsCApi::the()->record_stream(rate,bits,channels,name); +} + +extern "C" ARTSC_EXPORT void arts_backend_close_stream(arts_stream_t stream) +{ + if(!ArtsCApi::the()) return; + + arts_backend_debug("arts_backend_close_stream"); + ArtsCApi::the()->close_stream(stream); +} + +extern "C" ARTSC_EXPORT int arts_backend_read(arts_stream_t stream, void *buffer, int count) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_backend_read"); + return ArtsCApi::the()->read(stream,buffer,count); +} + +extern "C" ARTSC_EXPORT int arts_backend_write(arts_stream_t stream, const void *buffer, + int count) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_backend_write"); + return ArtsCApi::the()->write(stream,buffer,count); +} + +extern "C" ARTSC_EXPORT int arts_backend_stream_set(arts_stream_t stream, + arts_parameter_t param, int value) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_stream_set"); + return ArtsCApi::the()->stream_set(stream,param,value); +} + +extern "C" ARTSC_EXPORT int arts_backend_stream_get(arts_stream_t stream, + arts_parameter_t param) +{ + if(!ArtsCApi::the()) return ARTS_E_NOINIT; + + arts_backend_debug("arts_stream_get"); + return ArtsCApi::the()->stream_get(stream,param); +} -- cgit v1.2.1