summaryrefslogtreecommitdiffstats
path: root/soundserver/soundserverv2_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'soundserver/soundserverv2_impl.cc')
-rw-r--r--soundserver/soundserverv2_impl.cc386
1 files changed, 386 insertions, 0 deletions
diff --git a/soundserver/soundserverv2_impl.cc b/soundserver/soundserverv2_impl.cc
new file mode 100644
index 0000000..0abe5c7
--- /dev/null
+++ b/soundserver/soundserverv2_impl.cc
@@ -0,0 +1,386 @@
+ /*
+
+ Copyright (C) 2001 Jeff Tranter
+ tranter@kde.org
+ 2001 Stefan Westerfeld
+ stefan@space.twc.de
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Permission is also granted to link this program with the Qt
+ library, treating Qt like a library that normally accompanies the
+ operating system kernel, whether or not that is in fact the case.
+
+ */
+
+#include "artsflow.h"
+#include "flowsystem.h"
+#include "audiosubsys.h"
+#include "connect.h"
+#include "debug.h"
+#include "soundserverv2_impl.h"
+#include "artsversion.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fstream>
+#include <set>
+#include <cstring>
+#include <cstdlib>
+
+#include "config.h"
+
+using namespace Arts;
+using namespace std;
+
+SoundServerV2_impl::SoundServerV2_impl()
+ : _sampleStorage(SampleStorage(
+ MCOPUtils::createFilePath("artsd-samples"),true))
+{
+ checkNewObjects();
+}
+
+std::string SoundServerV2_impl:: audioMethod() {
+ return AudioSubSystem::the()->audioIO();
+}
+
+long SoundServerV2_impl:: samplingRate() {
+ return AudioSubSystem::the()->samplingRate();
+}
+
+long SoundServerV2_impl:: channels() {
+ return AudioSubSystem::the()->channels();
+}
+
+long SoundServerV2_impl:: bits() {
+ return AudioSubSystem::the()->bits();
+}
+
+bool SoundServerV2_impl:: fullDuplex() {
+ return AudioSubSystem::the()->fullDuplex();
+}
+
+std::string SoundServerV2_impl:: audioDevice() {
+ return AudioSubSystem::the()->deviceName();
+}
+
+long SoundServerV2_impl::fragments() {
+ return AudioSubSystem::the()->fragmentCount();
+}
+
+long SoundServerV2_impl::fragmentSize() {
+ return AudioSubSystem::the()->fragmentSize();
+}
+
+long SoundServerV2_impl::autoSuspendSeconds() {
+ return autoSuspendTime;
+}
+
+void SoundServerV2_impl::autoSuspendSeconds(long int newValue) {
+ autoSuspendTime = newValue;
+}
+
+std::string SoundServerV2_impl::version() {
+ return ARTS_VERSION;
+}
+
+long SoundServerV2_impl::bufferSizeMultiplier() {
+ return bufferMultiplier;
+}
+
+void SoundServerV2_impl::bufferSizeMultiplier(long newValue) {
+ bufferMultiplier = newValue;
+}
+
+StereoVolumeControl SoundServerV2_impl::outVolume() {
+ return _outVolume;
+}
+
+SampleStorage SoundServerV2_impl::sampleStorage() {
+ return _sampleStorage;
+}
+
+PlayObject SoundServerV2_impl::createPlayObjectForURL(const std::string& url, const std::string& mimetype, bool createBUS)
+{
+ arts_debug("search playobject, mimetype = %s", mimetype.c_str());
+
+ TraderQuery query;
+ query.supports("Interface","Arts::PlayObject");
+ query.supports("MimeType", mimetype);
+
+ string objectType;
+
+ vector<TraderOffer> *offers = query.query();
+ if(!offers->empty())
+ objectType = offers->front().interfaceName(); // first offer
+
+ delete offers;
+
+ /*
+ * create a PlayObject and connect it
+ */
+ if(!objectType.empty())
+ {
+ arts_debug("creating %s to play file", objectType.c_str());
+
+ PlayObject result = SubClass(objectType);
+ if(result.loadMedia(url))
+ {
+ if(createBUS)
+ {
+ // TODO: check for existence of left & right streams
+ Synth_BUS_UPLINK uplink;
+ uplink.busname("out_soundcard");
+ connect(result,"left",uplink,"left");
+ connect(result,"right",uplink,"right");
+ uplink.start();
+ result._node()->start();
+ result._addChild(uplink,"uplink");
+ return result;
+ }
+ else
+ return result;
+ }
+ else arts_warning("couldn't load file %s", url.c_str());
+ }
+ else arts_warning("mimetype %s unsupported", mimetype.c_str());
+
+ return PlayObject::null();
+}
+
+PlayObject SoundServerV2_impl::createPlayObjectForStream(InputStream instream, const std::string& mimetype, bool createBUS)
+{
+ arts_debug("search streamplayobject, mimetype = %s", mimetype.c_str());
+
+ TraderQuery query;
+ query.supports("Interface","Arts::StreamPlayObject");
+ query.supports("MimeType", mimetype);
+
+ string objectType;
+
+ vector<TraderOffer> *offers = query.query();
+ if(!offers->empty())
+ objectType = offers->front().interfaceName(); // first offer
+
+ delete offers;
+
+ /*
+ * create a PlayObject and connect it
+ */
+ if(!objectType.empty())
+ {
+ arts_debug("creating %s to play file", objectType.c_str());
+
+ StreamPlayObject result = SubClass(objectType);
+ result.streamMedia(instream);
+
+ if(createBUS)
+ {
+ // TODO: check for existence of left & right streams
+ Synth_BUS_UPLINK uplink;
+ uplink.busname("out_soundcard");
+ connect(result,"left",uplink,"left");
+ connect(result,"right",uplink,"right");
+ uplink.start();
+ result._node()->start();
+ result._addChild(uplink,"uplink");
+ return result;
+ }
+ else
+ return result;
+ }
+ else arts_warning("mimetype %s unsupported for streaming", mimetype.c_str());
+
+ return PlayObject::null();
+}
+
+static void clearDirectory(const string& directory)
+{
+ DIR *dir = opendir(directory.c_str());
+ if(!dir) return;
+
+ struct dirent *de;
+ while((de = readdir(dir)) != 0)
+ {
+ string currentEntry = directory + "/" + de->d_name;
+
+ if(de->d_name[0] != '.')
+ {
+ unlink(currentEntry.c_str());
+ }
+ }
+ closedir(dir);
+}
+
+/* copied from mcopidl */
+static void doTypeIndex(string dir, string prefix, ModuleDef& module)
+{
+ FILE *typeIndex = fopen((dir+"/"+prefix+".mcopclass").c_str(),"w");
+
+ vector<string> supportedTypes;
+
+ vector<InterfaceDef>::iterator ii;
+ for(ii = module.interfaces.begin(); ii != module.interfaces.end(); ii++)
+ supportedTypes.push_back(ii->name);
+
+ vector<TypeDef>::iterator ti;
+ for(ti = module.types.begin(); ti != module.types.end(); ti++)
+ supportedTypes.push_back(ti->name);
+
+ string supportedTypesList;
+ vector<string>::iterator si;
+ bool first = true;
+ for(si = supportedTypes.begin(); si != supportedTypes.end(); si++)
+ {
+ if(!first) supportedTypesList += ",";
+
+ supportedTypesList += (*si);
+ first = false;
+ }
+ fprintf(typeIndex, "# this file was generated by artsd - do not edit\n");
+ fprintf(typeIndex,"Type=%s\n",supportedTypesList.c_str());
+ fprintf(typeIndex,"TypeFile=%s.mcoptype\n",prefix.c_str());
+ fclose(typeIndex);
+}
+
+void SoundServerV2_impl::checkNewObjects()
+{
+ const char *home = getenv("HOME");
+ arts_return_if_fail(home != 0);
+
+ string dir = home + string("/.mcop/trader-cache");
+ string dataVersionFileName = dir + "/cache-data-version";
+
+ mkdir(home,0755);
+ mkdir((home+string("/.mcop")).c_str(),0755);
+ if(mkdir(dir.c_str(),0755) != 0)
+ {
+ string why = strerror(errno);
+
+ struct stat st;
+ stat(dir.c_str(),&st);
+ if(!S_ISDIR(st.st_mode))
+ {
+ arts_warning("can't create directory %s to fill it with"
+ " trader data (%s)", dir.c_str(), why.c_str());
+ return;
+ }
+ }
+
+ TraderQuery query;
+ query.supports("Interface", "Arts::Loader");
+ vector<TraderOffer> *offers = query.query();
+ vector<TraderOffer>::iterator i;
+
+ set<string> newDataVersion, cacheDataVersion;
+ for(i = offers->begin(); i != offers->end(); i++)
+ {
+ // TODO: error checking?
+ Arts::Loader loader = SubClass(i->interfaceName());
+ newDataVersion.insert(loader.dataVersion());
+ }
+
+ /* change this line if you change the cache update code */
+ newDataVersion.insert("Cache-Update-Code-Version:1.0");
+
+ /* load cache-data-version file */
+ {
+ ifstream infile(dataVersionFileName.c_str());
+
+ string line;
+ while(infile >> line)
+ cacheDataVersion.insert(line);
+ }
+
+ /* if it differs, rebuild trader cache */
+ if(cacheDataVersion != newDataVersion)
+ {
+ clearDirectory(dir);
+
+ /* save new cache-data-version file */
+ {
+ ofstream out(dataVersionFileName.c_str());
+
+ set<string>::iterator i;
+ for(i = newDataVersion.begin(); i != newDataVersion.end(); i++)
+ out << *i << endl;
+ }
+ rebuildTraderCache(dir, offers);
+ }
+ delete offers;
+}
+
+void SoundServerV2_impl::rebuildTraderCache(const string& directory,
+ vector<TraderOffer> *offers)
+{
+ vector<TraderOffer>::iterator i;
+
+ for(i = offers->begin(); i != offers->end(); i++)
+ {
+ // TODO: error checking?
+ Arts::Loader loader = SubClass(i->interfaceName());
+
+ /* put trader-information in ~/.mcop/trader-cache */
+ vector<TraderEntry> *entries = loader.traderEntries();
+ vector<TraderEntry>::iterator ei;
+ for(ei = entries->begin(); ei != entries->end(); ei++)
+ {
+ const TraderEntry& entry = *ei;
+
+ FILE *traderFile = fopen((directory+"/"+entry.interfaceName+".mcopclass").c_str(),"w");
+ fprintf(traderFile, "# this file was generated by artsd - do not edit\n");
+ vector<string>::const_iterator li;
+ for(li = entry.lines.begin(); li != entry.lines.end(); li++)
+ fprintf(traderFile,"%s\n", li->c_str());
+
+ fclose(traderFile);
+ }
+ delete entries;
+
+ /* put type-information in ~/.mcop/trader-cache */
+ vector<ModuleDef> *modules = loader.modules();
+ vector<ModuleDef>::iterator mi;
+ for(mi = modules->begin(); mi != modules->end(); mi++)
+ {
+ Arts::ModuleDef& module = *mi;
+
+ Buffer b;
+ module.writeType(b);
+
+ FILE *typeFile = fopen((directory + "/" + module.moduleName+".arts.mcoptype").c_str(),"w");
+ unsigned long towrite = b.size();
+ fwrite(b.read(towrite),1,towrite,typeFile);
+ fclose(typeFile);
+
+ doTypeIndex(directory,module.moduleName+".arts",module);
+ }
+ delete modules;
+ }
+ Dispatcher::the()->reloadTraderData();
+}
+
+float SoundServerV2_impl::cpuUsage()
+{
+ return CPUUsage::the()->usage() * 100.0;
+}
+
+
+#ifndef __SUNPRO_CC
+/* See bottom of simplesoundserver_impl.cc for the reason this is here. */
+REGISTER_IMPLEMENTATION(SoundServerV2_impl);
+#endif