diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | e2de64d6f1beb9e492daf5b886e19933c1fa41dd (patch) | |
tree | 9047cf9e6b5c43878d5bf82660adae77ceee097a /noatun/library/engine.cpp | |
download | tdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.tar.gz tdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdemultimedia@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'noatun/library/engine.cpp')
-rw-r--r-- | noatun/library/engine.cpp | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/noatun/library/engine.cpp b/noatun/library/engine.cpp new file mode 100644 index 00000000..e937fa7f --- /dev/null +++ b/noatun/library/engine.cpp @@ -0,0 +1,589 @@ +// $Id$ + +#include <noatun/engine.h> +#include <noatun/equalizer.h> +#include <noatun/player.h> +#include <noatun/plugin.h> +#include <noatun/effects.h> +#include "titleproxy.h" + +#include <string.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <kstandarddirs.h> +#include <kconfig.h> +#include <kdebug.h> +#include <qfile.h> +#include <qdir.h> +#include <sys/wait.h> +#include <kplayobject.h> +#include <kplayobjectfactory.h> + +#include <dynamicrequest.h> +#include <soundserver.h> +#include <kmedia2.h> +#include <flowsystem.h> +#include <noatunarts.h> +#include <connect.h> +#include <cpuinfo.h> + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <math.h> + + +static Arts::PlayObject nullPO() { return Arts::PlayObject::null(); } + +#define HARDWARE_VOLUME + +#if defined(__osf__) +#undef HARDWARE_VOLUME +#elif defined(__linux__) +#include <sys/soundcard.h> +#elif defined(__FreeBSD__) +#include <sys/soundcard.h> +#elif defined(__NetBSD__) +#include <soundcard.h> +#elif defined(___SOMETHING_UNKNOWN__) +#include <sys/soundcard.h> +#elif defined(_UNIXWARE) +#include <sys/soundcard.h> +#else +#undef HARDWARE_VOLUME +#endif + +using namespace std; + +namespace VolumeControls +{ + struct VC + { + virtual ~VC() {} + virtual void setVolume(int percent)=0; + virtual int volume() const =0; + }; + +#ifdef HARDWARE_VOLUME + + struct Hardware : public VC + { + Hardware(Engine *) + { + if ((fd=::open( "/dev/mixer", O_RDWR)) < 0) + { + return; + } + else + { +#define ERROR { fd=-1; return; } + int devmask, recmask, i_recsrc, stereodevs; + // Mixer is open. Now define properties + if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) ERROR + if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) ERROR + if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &i_recsrc) == -1) ERROR + if (ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs) == -1) ERROR + if (!devmask) ERROR +#undef ERROR + } + + } + + virtual ~Hardware() { ::close(fd); } + + virtual void setVolume(int percent) + { + percent=percent+(percent<<8); + ioctl(fd, MIXER_WRITE(4), &percent); + } + + virtual int volume() const + { + int volume, left, right; + left=100; + if (ioctl(fd, MIXER_READ(4), &volume) != -1) + { + left=volume & 0x7f; + right=(volume>>8) & 0x7f; + left=(left+right)/2; + } + return left; + } + private: + int fd; + }; +#endif + + struct SoftwareSSE : public VC + { + SoftwareSSE(Engine *e) : mVolume(100) + { + volumeControl = Arts::DynamicCast(e->server()->createObject("Noatun::StereoVolumeControlSSE")); + + if(volumeControl.isNull()) + volumeControl = Arts::DynamicCast(e->server()->createObject("Noatun::StereoVolumeControl")); + + volumeControl.start(); + + id=e->globalEffectStack()->insertBottom(volumeControl,"Volume Control"); + } + + virtual void setVolume(int percent) + { + mVolume=percent; + float vol = pow(2.0, ((400 - (100-percent)*12)/200.0))/4.0; + if (percent == 0) vol = 0.0; + if (!volumeControl.isNull()) + volumeControl.percent(vol); + } + + virtual int volume() const + { + return mVolume; + } + + private: + Noatun::StereoVolumeControlSSE volumeControl; + long id; + int mVolume; + }; + + struct Software : public VC + { + Software(Engine *e) : mVolume(100) + { + volumeControl = Arts::DynamicCast(e->server()->createObject("Noatun::StereoVolumeControl")); + volumeControl.start(); + + id=e->globalEffectStack()->insertBottom(volumeControl,"Volume Control"); + } + + virtual void setVolume(int percent) + { + mVolume=percent; + if (!volumeControl.isNull()) + volumeControl.percent((float)percent/100.0); + } + + virtual int volume() const + { + return mVolume; + } + + private: + Noatun::StereoVolumeControl volumeControl; + long id; + int mVolume; + }; + + static VC *volumeControl(Engine *e) + { +#ifdef HARDWARE_VOLUME + if (napp->fastMixer()) + return new Hardware(e); + else + { +#endif + if (!getenv("NO_SSE") && Arts::CpuInfo::flags()&Arts::CpuInfo::CpuSSE) + return new SoftwareSSE(e); + else + return new Software(e); + +#ifdef HARDWARE_VOLUME + } +#endif + } +} + + +class Engine::EnginePrivate +{ +public: + EnginePrivate() + : playobj(0), + server(Arts::SoundServerV2::null()), + globalEffectStack(Noatun::StereoEffectStack::null()), + effectsStack(Noatun::StereoEffectStack::null()), + visStack(Noatun::StereoEffectStack::null()), + volumeControl(0), session(Noatun::Session::null()), + pProxy(0) + { + } + + ~EnginePrivate() + { + visStack=Noatun::StereoEffectStack::null(); + } + + KDE::PlayObject *playobj; + Arts::SoundServerV2 server; + Arts::Synth_AMAN_PLAY amanPlay; + + // globalEffectStack + // |- effectsStack + // |- Effects... + // |- visStack + // |- Visualizations + // |- Volume Control + // + Noatun::StereoEffectStack globalEffectStack; + Noatun::StereoEffectStack effectsStack; + Noatun::StereoEffectStack visStack; + Noatun::Equalizer equalizer; + + int volumeID; + VolumeControls::VC *volumeControl; + Noatun::Session session; + TitleProxy::Proxy *pProxy; +}; + +Arts::SoundServerV2 *Engine::server() const { return &d->server;} +Arts::PlayObject Engine::playObject() const { return d->playobj ? d->playobj->object() : nullPO(); } +Arts::SoundServerV2 *Engine::simpleSoundServer() const { return &d->server; } +Noatun::StereoEffectStack *Engine::effectStack() const { return &d->effectsStack; } +Noatun::StereoEffectStack *Engine::visualizationStack() const { return &d->visStack; } +Noatun::StereoEffectStack *Engine::globalEffectStack() const { return &d->globalEffectStack; } +Noatun::Equalizer *Engine::equalizer() const { return &d->equalizer; } +Noatun::Session *Engine::session() const { return &d->session; } + +Engine::Engine(QObject *parent) : QObject(parent, "Engine"), mPlay(false) +{ + d=new EnginePrivate; + // Connect to aRts + if (!initArts()) + { + KMessageBox::error(0, i18n("There was an error communicating to the aRts daemon."), i18n("aRts error")); + exit(0); + } + +} + +Engine::~Engine() +{ + stop(); + delete d->volumeControl; + d->server=Arts::SoundServerV2::null(); + delete d; +} + +void Engine::setInitialized() +{ + mPlay=true; +} + +bool Engine::initialized() const +{ + return mPlay; +} + +bool Engine::open(const PlaylistItem &file) +{ + if(!initArts()) + return false; + + d->playobj = 0; + + KDE::PlayObjectFactory factory(d->server); + + if (file.isProperty("stream_") && file.url().protocol() == "http") + { + deleteProxy(); + d->pProxy = new TitleProxy::Proxy(KURL(file.property("stream_"))); + d->playobj = factory.createPlayObject(d->pProxy->proxyUrl(), false); + + connect(d->playobj, SIGNAL(destroyed()), this, SLOT(deleteProxy())); + connect( + d->pProxy, SIGNAL( + metaData( + const QString &, const QString &, + const QString &, const QString &, + const QString &, const QString &)), + this, SIGNAL( + receivedStreamMeta(const QString &, const QString &, + const QString &, const QString &, + const QString &, const QString &)) + ); + connect(d->pProxy, SIGNAL(proxyError()), this, SLOT(slotProxyError())); + } + else + { + d->playobj = factory.createPlayObject(file.url(), false); + } + + if (!d->playobj || d->playobj->isNull()) + { + kdDebug(66666) << k_funcinfo << + "No playobject for '" << file.url().prettyURL() << "'" << endl; + delete d->playobj; + d->playobj=0; + emit playingFailed(); + return false; + } + + if ( !d->playobj->object().isNull() ) + { + connectPlayObject(); + } + else + { + connect( d->playobj, SIGNAL( playObjectCreated() ), this, SLOT( connectPlayObject() ) ); + } + + if (mPlay) + d->playobj->play(); + + return true; +} + +void Engine::slotProxyError() +{ + kdDebug(66666) << k_funcinfo << endl; + emit playingFailed(); + deleteProxy(); +} + +void Engine::deleteProxy() +{ + delete d->pProxy; + d->pProxy = 0; +} + +void Engine::connectPlayObject() +{ + if (d->playobj->object().isNull()) + { + emit playingFailed(); + return; + } + d->playobj->object()._node()->start(); + + // TODO: check for existence of left & right streams + Arts::connect(d->playobj->object(),"left",d->globalEffectStack,"inleft"); + Arts::connect(d->playobj->object(),"right",d->globalEffectStack,"inright"); + + emit aboutToPlay(); +} + +bool Engine::play() +{ + if (!mPlay) return true; + if(!d->playobj) + return false; + d->playobj->play(); + return true; +} + +void Engine::pause() +{ + d->playobj->pause(); +} + +void Engine::stop() +{ + if(!d->playobj) return; + + d->playobj->halt(); + delete d->playobj; + d->playobj=0; +} + +void Engine::seek(int msec) // pass time in msecs +{ + if(!d->playobj) return; + + Arts::poTime t; + + t.custom = 0.0; + t.ms = (long) msec % 1000; + t.seconds = (long) (msec - t.ms) / 1000; + + if(d->playobj) + d->playobj->seek(t); +} + +int Engine::position() +{ + if(!d->playobj) return -1; + + Arts::poTime time(d->playobj->currentTime()); + return (int)(time.ms + (time.seconds*1000)); // return position in milliseconds +} + +int Engine::length() +{ + if(!d->playobj) return -1; + if (!(d->playobj->capabilities() & Arts::capSeek)) + return -1; + + Arts::poTime time(d->playobj->overallTime()); + return (int)(time.ms + (time.seconds*1000)); // return track-length in milliseconds +} + +int Engine::state() +{ + if(d->playobj) + return d->playobj->state(); + else + return Arts::posIdle; +} + +void Engine::setVolume(int percent) +{ + if (percent>100) + percent=100; + if (percent<0) + percent=0; + d->volumeControl->setVolume(percent); +} + +int Engine::volume() const +{ + return d->volumeControl->volume(); +} + +void Engine::useHardwareMixer(bool) +{ + delete d->volumeControl; + d->volumeControl=VolumeControls::volumeControl(this); +} + +bool Engine::initArts() +{ + if ( d->server.isNull() || d->server.error() ) + { + d->server = Arts::Reference("global:Arts_SoundServerV2"); + int volume = d->volumeControl ? d->volumeControl->volume() : -1; + delete d->volumeControl; + d->volumeControl=0; + + if( d->server.isNull() || d->server.error() ) + { + // aRts seems not to be running, let's try to run it + // First, let's read the configuration as in kcmarts + KConfig config("kcmartsrc"); + QCString cmdline; + + config.setGroup("Arts"); + + bool rt = config.readBoolEntry("StartRealtime",false); + bool x11Comm = config.readBoolEntry("X11GlobalComm",false); + + // put the value of x11Comm into .mcoprc + { + KConfig X11CommConfig(QDir::homeDirPath()+"/.mcoprc"); + + if(x11Comm) + X11CommConfig.writeEntry("GlobalComm", "Arts::X11GlobalComm"); + else + X11CommConfig.writeEntry("GlobalComm", "Arts::TmpGlobalComm"); + + X11CommConfig.sync(); + } + + cmdline = QFile::encodeName(KStandardDirs::findExe(QString::fromLatin1("kdeinit_wrapper"))); + cmdline += " "; + + if (rt) + cmdline += QFile::encodeName(KStandardDirs::findExe( + QString::fromLatin1("artswrapper"))); + else + cmdline += QFile::encodeName(KStandardDirs::findExe( + QString::fromLatin1("artsd"))); + + cmdline += " "; + cmdline += config.readEntry("Arguments","-F 10 -S 4096 -s 60 -m artsmessage -l 3 -f").utf8(); + + int status=::system(cmdline); + + if ( status!=-1 && WIFEXITED(status) ) + { + // We could have a race-condition here. + // The correct way to do it is to make artsd fork-and-exit + // after starting to listen to connections (and running artsd + // directly instead of using kdeinit), but this is better + // than nothing. + int time = 0; + do + { + // every time it fails, we should wait a little longer + // between tries + ::sleep(1+time/2); + d->server = Arts::Reference("global:Arts_SoundServerV2"); + } while(++time < 5 && (d->server.isNull())); + } + } + + if ( !d->server.isNull() ) + { + d->amanPlay = Arts::DynamicCast( + d->server.createObject("Arts::Synth_AMAN_PLAY") + ); + + if (d->amanPlay.isNull()) + goto crapOut; + + d->session = Arts::DynamicCast( + d->server.createObject("Noatun::Session")); + if (d->session.isNull()) + { + kdWarning() << "Couldn't instanciate artsobject Noatun::Session. " + << "(This is normally caused by a broken package or " + << "compiling kdemultimedia in a --prefix different " + << "from arts. It may also be from two conflicting " + << "packages, so uninstall every arts/artsd package " + << "you have installed and try again." << endl; + goto crapOut; + } + + d->amanPlay.title("noatun"); + d->amanPlay.autoRestoreID("noatun"); + d->amanPlay.start(); + + d->globalEffectStack=Arts::DynamicCast( + d->server.createObject("Noatun::StereoEffectStack"));; + d->globalEffectStack.start(); + Arts::connect(d->globalEffectStack,d->amanPlay); + + d->effectsStack=Arts::DynamicCast( + d->server.createObject("Noatun::StereoEffectStack")); + d->effectsStack.start(); + d->globalEffectStack.insertBottom(d->effectsStack, "Effects Stack"); + + d->equalizer=Arts::DynamicCast(d->server.createObject("Noatun::Equalizer")); + d->equalizer.start(); + d->globalEffectStack.insertBottom(d->equalizer, "Equalizer"); + + if (napp->equalizer()) + { + napp->equalizer()->update(true); + napp->equalizer()->setPreamp(napp->equalizer()->preamp()); + napp->equalizer()->setEnabled(napp->equalizer()->isEnabled()); + } + + d->visStack=Arts::DynamicCast( + d->server.createObject("Noatun::StereoEffectStack")); + d->visStack.start(); + + d->globalEffectStack.insertBottom(d->visStack, "Visualization Stack"); + d->volumeControl=VolumeControls::volumeControl(this); + if (volume != -1) + d->volumeControl->setVolume(volume); + } + else + { + crapOut: + KMessageBox::error( 0, i18n("Connecting/starting aRts soundserver failed. Make sure that artsd is configured properly.")); + exit(1); + } + } + + d->playobj=0; + emit artsError(); + return true; +} + + +#include "engine.moc" + |