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.
arts/soundserver/soundserverv2_impl.cc

387 lines
9.7 KiB

/*
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 <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