/* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 #include #include #include #include #include #include #include #include #include #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 *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 *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 supportedTypes; vector::iterator ii; for(ii = module.interfaces.begin(); ii != module.interfaces.end(); ii++) supportedTypes.push_back(ii->name); vector::iterator ti; for(ti = module.types.begin(); ti != module.types.end(); ti++) supportedTypes.push_back(ti->name); string supportedTypesList; vector::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 *offers = query.query(); vector::iterator i; set 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::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 *offers) { vector::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 *entries = loader.traderEntries(); vector::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::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 *modules = loader.modules(); vector::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