?? helix-engine.cpp
字號:
/*************************************************************************** * Copyright (C) 2005 Paul Cifarelli * * * * 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. * * * ***************************************************************************/#include <qthread.h>#include <sys/param.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <climits>#include <cmath>#include <stdarg.h>#include <config.h>#include <iostream>#include "debug.h"#include <klocale.h>#include <kmessagebox.h>#include <qapplication.h>#include <qdir.h>#include <qstringlist.h>#include "helix-engine.h"#include "helix-configdialog.h"#include "config/helixconfig.h"#include "helix-errors.h"#include "helix-sp.h"#include "hxplayercontrol.h"#include "amarokconfig.h"AMAROK_EXPORT_PLUGIN( HelixEngine )#define DEBUG_PREFIX "helix-engine"using namespace std;extern "C"{ #include <unistd.h>}#define HELIX_ENGINE_TIMER 10 // 10 ms timer#define SCOPE_MAX_BEHIND 200 // 200 postmix buffers#ifndef LLONG_MAX#define LLONG_MAX 9223372036854775807LL#endif///returns the configuration we will usestatic inline QCString configPath() { return QFile::encodeName( QDir::homeDirPath() + "/.helix/config" ); }HelixEngine::HelixEngine() : EngineBase(), PlayerControl(), m_state(Engine::Empty), m_coredir(HELIX_LIBS "/common"), m_pluginsdir(HELIX_LIBS "/plugins"), m_codecsdir(HELIX_LIBS "/codecs"), m_inited(false), m_scopeplayerlast(0), m_sfps(0.0), m_scopedelta(0), m_sframes(0), m_lframes(0){ addPluginProperty( "HasConfigure", "true" ); addPluginProperty( "HasEqualizer", "true" ); addPluginProperty( "HasCrossfade", "true" ); addPluginProperty( "HasCDDA", "false"); memset(&m_md, 0, sizeof(m_md)); memset(hscope, 0, 2*sizeof(HelixScope)); memset(&m_scopetm, 0, sizeof(struct timeval)); memset(m_pfade, 0, 2*sizeof(FadeTrack));}HelixEngine::~HelixEngine(){ m_mimes.clear();}int HelixEngine::print2stdout(const char *fmt, ...){ va_list args; char buf[1024]; va_start(args, fmt); int ret = vsprintf(buf, fmt, args); debug() << buf; va_end(args); return ret;}int HelixEngine::print2stderr(const char *fmt, ...){ va_list args; char buf[1024]; va_start(args, fmt); int ret = vsprintf(buf, fmt, args); debug() << buf; va_end(args); return ret;}void HelixEngine::notifyUser(unsigned long code, const char *moreinfo, const char *moreinfourl){ QString *err = HelixErrors::errorText(code); if (err) emit statusText(i18n("Helix Core returned error: %1 %2 %3").arg(QString(*err)).arg(QString(moreinfo)).arg(QString(moreinfourl))); else emit statusText(i18n("Helix Core returned error: <unknown>"));}void HelixEngine::interruptUser(unsigned long code, const char *moreinfo, const char *moreinfourl){ QString *err = HelixErrors::errorText(code); if (err) emit infoMessage(i18n("Helix Core returned error: %1 %1 %1").arg(QString(*err)).arg(QString(moreinfo)).arg(QString(moreinfourl))); else emit infoMessage(i18n("Helix Core returned error: <unknown>")); // since this is a serious error, emit trackEnded so amarok knows to move on play_finished( m_current );}void HelixEngine::onContacting(const char *host){ emit statusText( i18n("Contacting: %1").arg( QString(host) ) );}void HelixEngine::onBuffering(int pcnt){ if (pcnt != 100) // let's not report that... emit statusText( i18n( "Buffering %1%" ).arg( pcnt ) );}Amarok::PluginConfig*HelixEngine::configure() const{ debug() << "Starting HelixConfigDialog\n"; return new HelixConfigDialog( (HelixEngine *)this );}int HelixEngine::fallbackToOSS(){ KMessageBox::information( 0, i18n("The helix library you have configured does not support ALSA, the helix-engine has fallen back to OSS") ); debug() << "Falling back to OSS\n"; return (HelixConfigDialog::setSoundSystem( (int) HelixSimplePlayer::OSS ));}boolHelixEngine::init(){ debug() << "Initializing HelixEngine\n"; struct stat s; bool exists = false; stop(); m_state = Engine::Empty; m_numPlayers = 2; m_current = 1; m_coredir = HelixConfig::coreDirectory(); if (m_coredir.isEmpty()) m_coredir = HELIX_LIBS "/common"; m_pluginsdir = HelixConfig::pluginDirectory(); if (m_pluginsdir.isEmpty()) m_pluginsdir = HELIX_LIBS "/plugins"; m_codecsdir = HelixConfig::codecsDirectory(); if (m_codecsdir.isEmpty()) m_codecsdir = HELIX_LIBS "/codecs"; if (HelixConfig::outputplugin() == "oss") setOutputSink( HelixSimplePlayer::OSS ); else { setOutputSink( HelixSimplePlayer::ALSA ); if (HelixConfig::deviceenabled()) setDevice( HelixConfig::device().utf8() ); else setDevice("default"); } if (!stat(m_coredir.utf8(), &s) && !stat(m_pluginsdir.utf8(), &s) && !stat(m_codecsdir.utf8(), &s)) { long vol=0; bool eqenabled=false; int savedpreamp=0; QValueList<int> savedequalizerGains; if (m_inited) { vol = PlayerControl::getVolume(); eqenabled = PlayerControl::isEQenabled(); for (unsigned int i=0; i < m_equalizerGains.size(); i++) savedequalizerGains.append(m_equalizerGains[i]); savedpreamp = m_preamp; PlayerControl::tearDown(); } PlayerControl::init(m_coredir.utf8(), m_pluginsdir.utf8(), m_codecsdir.utf8(), 2); if (PlayerControl::initDirectSS()) { fallbackToOSS(); PlayerControl::initDirectSS(); } if (m_inited) { PlayerControl::setVolume(vol); setEqualizerEnabled(eqenabled); setEqualizerParameters(savedpreamp, savedequalizerGains); } m_inited = exists = true; } if (!exists || PlayerControl::getError()) { KMessageBox::error( 0, i18n("The Helix Engine requires the RealPlayer(tm) or HelixPlayer libraries to be installed. Please make sure one is installed, and adjust the paths in \"Amarok Settings\" -> \"Engine\"") ); // we need to return true here so that the user has an oppportunity to change the directory //return false; return true; } // create a list of mime types and ext for use in canDecode() m_mimes.resize( getMimeListLen() ); int i = 0; const MimeList *ml = getMimeList(); MimeEntry *entry; while (ml) { QString mt = ml->mimetypes; QString me = ml->mimeexts; entry = new MimeEntry; entry->type = QStringList::split('|', mt); entry->ext = QStringList::split('|', me); m_mimes[i] = *entry; debug() << ml->mimetypes << endl; i++; ml = ml->fwd; } debug() << "Succussful init\n"; return true;}boolHelixEngine::load( const KURL &url, bool isStream ){ debug() << "In load " << url.url() << endl; if (!m_inited) return false; if (!canDecode(url)) { const QString path = url.path(); const QString ext = path.mid( path.findRev( '.' ) + 1 ).lower(); emit statusText( i18n("No plugin found for the %1 format").arg(ext) ); return false; } debug() << "xfadeLength is " << m_xfadeLength << endl; if( m_xfadeLength > 0 && m_state == Engine::Playing && !isStream && ( m_xfadeNextTrack || //set by engine controller when switching tracks automatically (uint) AmarokConfig::crossfadeType() == 0 || //crossfade always (uint) AmarokConfig::crossfadeType() == 2 ) ) //crossfade when switching tracks manually) { //set m_xfadeNextTrack true here regardless to play() will work correctly; disable in there m_xfadeNextTrack = true; int nextPlayer = m_current ? 0 : 1; // prepare the next player PlayerControl::stop(nextPlayer); resetScope(nextPlayer); memset(&hscope[nextPlayer], 0, sizeof(HelixScope)); memset(&m_pfade[nextPlayer], 0, sizeof(FadeTrack)); if (isPlaying(m_current)) { m_pfade[m_current].m_fadeactive = true; m_pfade[m_current].m_startfadetime = PlayerControl::where(m_current); setFadeout(true, m_xfadeLength, m_current); } Engine::Base::load( url, false ); // we don't crossfade streams ?? do we load the base here ?? PlayerControl::setURL( QFile::encodeName( url.url() ), nextPlayer, !isStream ); m_isStream = false; } else cleanup(); m_isStream = isStream; int nextPlayer; nextPlayer = m_current ? 0 : 1; Engine::Base::load( url, isStream || url.protocol() == "http" ); m_state = Engine::Idle; emit stateChanged( Engine::Idle ); m_url = url; if (url.isLocalFile()) PlayerControl::setURL( QFile::encodeName( url.url() ), nextPlayer, !m_isStream ); else { m_isStream = true; PlayerControl::setURL( QFile::encodeName( url.url() ), nextPlayer, !m_isStream ); } return true;}boolHelixEngine::play( uint offset ){ debug() << "In play" << endl; int nextPlayer; if (!m_inited) return false; if (m_state != Engine::Playing) { struct timezone tz; memset(&tz, 0, sizeof(struct timezone)); gettimeofday(&m_scopetm, &tz); startTimer(HELIX_ENGINE_TIMER); } nextPlayer = m_current ? 0 : 1; if (m_xfadeLength && m_xfadeNextTrack && !offset && isPlaying(m_current)) { m_xfadeNextTrack = false; PlayerControl::start(nextPlayer, true, m_xfadeLength); } else PlayerControl::start(nextPlayer); if (offset) PlayerControl::seek( offset, nextPlayer ); if (!PlayerControl::getError()) { if (m_state != Engine::Playing) { m_state = Engine::Playing; emit stateChanged( Engine::Playing ); } m_current = nextPlayer; return true; } cleanup(); m_state = Engine::Empty; emit stateChanged( Engine::Empty ); return false;}voidHelixEngine::cleanup(){ if (!m_inited) return; m_url = KURL(); PlayerControl::stop(); // stop all players resetScope(0); resetScope(1); killTimers(); m_isStream = false; memset(&m_md, 0, sizeof(m_md)); memset(hscope, 0, 2*sizeof(HelixScope)); memset(m_pfade, 0, 2*sizeof(FadeTrack));}voidHelixEngine::stop(){ if (!m_inited) return; debug() << "In stop where=" << where(m_current) << " duration=" << duration(m_current) << endl; if( AmarokConfig::fadeout() && !m_pfade[m_current].m_fadeactive && state() == Engine::Playing ) { debug() << "fading out...\n"; m_state = Engine::Empty; emit stateChanged( Engine::Empty ); // tell the controller not to bother you anymore m_pfade[m_current].m_fadeactive = true; m_pfade[m_current].m_stopfade = true; m_pfade[m_current].m_startfadetime = PlayerControl::where(m_current); setFadeout(true, AmarokConfig::fadeoutLength(), m_current); } else { debug() << "Stopping immediately\n"; cleanup(); cleanUpStream(m_current); m_state = Engine::Empty; emit stateChanged( m_state ); }}void HelixEngine::play_finished(int playerIndex){ debug() << "Ok, finished playing the track\n"; cleanUpStream(playerIndex); resetScope(playerIndex); memset(&hscope[playerIndex], 0, sizeof(HelixScope)); memset(&m_pfade[playerIndex], 0, sizeof(FadeTrack)); if (playerIndex == m_current && !m_pfade[playerIndex].m_stopfade && !m_pfade[playerIndex].m_fadeactive)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -