/* 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. */ #include "artsflow.h" #include "flowsystem.h" #include "stdsynthmodule.h" #include "bus.h" using namespace Arts; using namespace std; namespace Arts { class AudioManagerClient_impl; class AudioManagerAssignable { public: virtual long ID() = 0; virtual void destination(const string& newDestination) = 0; }; #ifdef __SUNPRO_CC /* Bloody SunPRO CC has problems with instantiation of the below two templates, if the _clients and assignable member of AudioManager_impl are declared to be directly the type list. So instead be move a typedef in between, which makes it magically work. We could also use an explicit instantiation, but this is not allowed on all C++ compilers in this scope. Note also, that we don't need to replace _all_ occurrences of list below, only the two in the member declaration. What a mess. */ typedef list L_AMC; typedef list L_AMA; #else /* with normal compilers there is no need for this typedef. */ #define L_AMC list #define L_AMA list #endif class AudioManager_impl : virtual public AudioManager_skel { protected: L_AMC _clients; L_AMA assignable; long _changes, nextID; static AudioManager_impl *instance; public: AudioManager_impl() { assert(!instance); instance = this; _changes = 0; nextID = 1; } ~AudioManager_impl() { assert(instance); instance = 0; } vector *destinations() { return BusManager::the()->busList(); } long changes() { return _changes; } vector *clients(); void setDestination(long ID, const string& newDestination); AudioManagerClient_impl *findClient(long ID); // non MCOP interface static AudioManager_impl *the() { assert(instance); return instance; } long addClient(AudioManagerClient_impl *client) { _clients.push_back(client); _changes++; return nextID++; } void removeClient(AudioManagerClient_impl *client) { _changes++; _clients.remove(client); } void addAssignable(AudioManagerAssignable *a); void removeAssignable(AudioManagerAssignable *a) { assignable.remove(a); } }; AudioManager_impl *AudioManager_impl::instance = 0; class AudioManagerClient_impl :virtual public AudioManagerClient_skel { protected: string _title, _autoRestoreID; long _ID; AudioManagerDirection _direction; string _destination; public: AudioManagerClient_impl() { _ID = AudioManager_impl::the()->addClient(this); } ~AudioManagerClient_impl() { AudioManager_impl::the()->removeClient(this); } void title(const string& newvalue) { _title = newvalue; } string title() { return _title; } void autoRestoreID(const string& newvalue) { _autoRestoreID = newvalue; } string autoRestoreID() { return _autoRestoreID; } long ID() { return _ID; } AudioManagerDirection direction() { return _direction; } void direction(AudioManagerDirection newvalue) { _direction = newvalue; } void constructor(AudioManagerDirection cdirection, const string& ctitle, const string& cautoRestoreID) { direction(cdirection); title(ctitle); autoRestoreID(cautoRestoreID); } /* non MCOP interface */ string destination() { return _destination; } void destination(const string& newvalue) { _destination = newvalue; } }; // this suffers a tiny bit from copypasting due to simpler // inheritance hierarchy class Synth_AMAN_PLAY_impl :virtual public Synth_AMAN_PLAY_skel, virtual public AudioManagerAssignable, virtual public StdSynthModule { protected: Synth_BUS_UPLINK uplink; AudioManagerClient client; public: /* forward requests for title/autoRestoreID to client */ void title(const string& newvalue) { client.title(newvalue); } string title() { return client.title(); } void autoRestoreID(const string& newvalue) {client.autoRestoreID(newvalue);} string autoRestoreID() { return client.autoRestoreID(); } /* assign an already well-known client */ void constructor(AudioManagerClient client) { this->client = client; assert(client.direction() == amPlay); } Synth_AMAN_PLAY_impl() { // Set direction of the client to amPlay, but actually it would // be nice to do that only when we know we won't get a different client // to use. client.direction(amPlay); _node()->virtualize("left",uplink._node(),"left"); _node()->virtualize("right",uplink._node(),"right"); } void streamInit() { AudioManager_impl::the()->addAssignable(this); uplink.start(); } void streamEnd() { AudioManager_impl::the()->removeAssignable(this); uplink.stop(); } AutoSuspendState autoSuspend() { return asSuspend; } // Assignable: void destination(const string& destination) { uplink.busname(destination); } long ID() { return client.ID(); } }; // this suffers a tiny bit from copypasting due to simpler // inheritance hierarchy class Synth_AMAN_RECORD_impl :virtual public Synth_AMAN_RECORD_skel, virtual public AudioManagerAssignable, virtual public StdSynthModule { protected: Synth_BUS_DOWNLINK downlink; AudioManagerClient client; public: /* forward requests for title/autoRestoreID to client */ void title(const string& newvalue) { client.title(newvalue); } string title() { return client.title(); } void autoRestoreID(const string& newvalue) {client.autoRestoreID(newvalue);} string autoRestoreID() { return client.autoRestoreID(); } /* assign an already well-known client */ void constructor(AudioManagerClient client) { this->client = client; assert(client.direction() == amRecord); } Synth_AMAN_RECORD_impl() { // Set direction of the client to amRecord, but actually it would // be nice to do that only when we know we won't get a different client // to use. client.direction(amRecord); _node()->virtualize("left",downlink._node(),"left"); _node()->virtualize("right",downlink._node(),"right"); } void streamInit() { AudioManager_impl::the()->addAssignable(this); downlink.start(); } void streamEnd() { AudioManager_impl::the()->removeAssignable(this); downlink.stop(); } // Assignable: void destination(const string& destination){downlink.busname(destination);} long ID() { return client.ID(); } }; vector *AudioManager_impl::clients() { vector *result = new vector; list::iterator i; for(i = _clients.begin(); i != _clients.end(); i++) { AudioManagerClient_impl *client = *i; AudioManagerInfo info; info.ID = client->ID(); info.direction = client->direction(); info.title = client->title(); info.autoRestoreID = client->autoRestoreID(); info.destination = client->destination(); result->push_back(info); } return result; } AudioManagerClient_impl *AudioManager_impl::findClient(long ID) { list::iterator i; for(i = _clients.begin(); i != _clients.end(); i++) { AudioManagerClient_impl *client = *i; if(client->ID() == ID) return client; } return 0; } void AudioManager_impl::setDestination(long ID, const string& newDestination) { AudioManagerClient_impl *client = findClient(ID); if(client) { client->destination(newDestination); list::iterator i; for(i = assignable.begin(); i != assignable.end(); i++) { AudioManagerAssignable *a = *i; if(a->ID() == ID) a->destination(newDestination); } _changes++; } } void AudioManager_impl::addAssignable(AudioManagerAssignable *a) { // ensure that this client is assigned properly AudioManagerClient_impl *client = findClient(a->ID()); assert(client); if(client->destination().empty()) { // TODO: more flexible default assignment policies - load autoRestoreID // related stuff here (or somewhere else) switch(client->direction()) { case amPlay: client->destination("out_soundcard"); break; case amRecord: client->destination("in_soundcard"); break; } } assignable.push_back(a); a->destination(client->destination()); } REGISTER_IMPLEMENTATION(AudioManagerClient_impl); REGISTER_IMPLEMENTATION(AudioManager_impl); REGISTER_IMPLEMENTATION(Synth_AMAN_PLAY_impl); REGISTER_IMPLEMENTATION(Synth_AMAN_RECORD_impl); }