More engine fixes
This commit is contained in:
parent
67df8f2243
commit
04f1d296ea
@ -19,6 +19,9 @@
|
|||||||
project(strawberry)
|
project(strawberry)
|
||||||
cmake_minimum_required(VERSION 2.8.11)
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
cmake_policy(SET CMP0054 NEW)
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
if(${CMAKE_VERSION} VERSION_GREATER "3.10.3")
|
||||||
|
cmake_policy(SET CMP0072 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
include(CheckIncludeFiles)
|
include(CheckIncludeFiles)
|
||||||
|
17
dist/maketarball.sh.in
vendored
17
dist/maketarball.sh.in
vendored
@ -2,19 +2,26 @@
|
|||||||
|
|
||||||
name=strawberry
|
name=strawberry
|
||||||
version="@STRAWBERRY_VERSION_PACKAGE@"
|
version="@STRAWBERRY_VERSION_PACKAGE@"
|
||||||
|
gitrev="@INCLUDE_GIT_REVISION@"
|
||||||
root=$(cd "${0%/*}/.." && echo $PWD/${0##*/})
|
root=$(cd "${0%/*}/.." && echo $PWD/${0##*/})
|
||||||
root=`dirname "$root"`
|
root=`dirname "$root"`
|
||||||
rootnoslash=`echo $root | sed "s/^\///"`
|
rootnoslash=`echo $root | sed "s/^\///"`
|
||||||
|
|
||||||
|
if ! [ "$gitrev" = "ON" ]; then
|
||||||
|
exclude_vcs="--exclude-vcs"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Creating $name-$version.tar.xz..."
|
echo "Creating $name-$version.tar.xz..."
|
||||||
|
|
||||||
rm -f "$name-$version.tar.xz"
|
rm -f "$name-$version.tar.xz"
|
||||||
tar -cJf $name-$version.tar.xz \
|
tar -cJf $name-$version.tar.xz \
|
||||||
--transform "s,^$rootnoslash,$name-$version," \
|
--transform "s,^$rootnoslash,$name-$version," $exclude_vcs \
|
||||||
--exclude-vcs \
|
--exclude "*.tar" \
|
||||||
--exclude "$root/dist/*.tar" \
|
--exclude "*.tar.*" \
|
||||||
--exclude "$root/dist/*.tar.*" \
|
--exclude "*.bz" \
|
||||||
|
--exclude "*.bz2" \
|
||||||
|
--exclude "*.xz" \
|
||||||
|
--exclude ".directory" \
|
||||||
--exclude "$root/CMakeLists.txt.user" \
|
--exclude "$root/CMakeLists.txt.user" \
|
||||||
--exclude "$root/build" \
|
--exclude "$root/build" \
|
||||||
--exclude ".directory" \
|
|
||||||
"$root"
|
"$root"
|
||||||
|
@ -81,8 +81,7 @@ Player::Player(Application *app, QObject *parent)
|
|||||||
volume_before_mute_(50),
|
volume_before_mute_(50),
|
||||||
last_pressed_previous_(QDateTime::currentDateTime()),
|
last_pressed_previous_(QDateTime::currentDateTime()),
|
||||||
menu_previousmode_(PreviousBehaviour_DontRestart),
|
menu_previousmode_(PreviousBehaviour_DontRestart),
|
||||||
seek_step_sec_(10)
|
seek_step_sec_(10) {
|
||||||
{
|
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||||
@ -90,103 +89,86 @@ Player::Player(Application *app, QObject *parent)
|
|||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
CreateEngine(enginetype);
|
CreateEngine(enginetype);
|
||||||
|
|
||||||
settings_.beginGroup("Player");
|
settings_.beginGroup("Player");
|
||||||
|
|
||||||
SetVolume(settings_.value("volume", 100).toInt());
|
int volume = settings_.value("volume", 50).toInt();
|
||||||
|
SetVolume(volume);
|
||||||
#if 0
|
|
||||||
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
|
||||||
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
|
|
||||||
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player() {}
|
Player::~Player() {
|
||||||
|
settings_.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
EngineBase *Player::CreateEngine(Engine::EngineType enginetype) {
|
void Player::CreateEngine(Engine::EngineType enginetype) {
|
||||||
|
|
||||||
bool engine = false;
|
Engine::EngineType use_enginetype = Engine::None;
|
||||||
EngineBase *enginebase = nullptr;
|
|
||||||
|
|
||||||
for (int i = 1 ; !engine ; i++) {
|
for (int i = 0 ; use_enginetype == Engine::None ; i++) {
|
||||||
switch(enginetype) {
|
switch(enginetype) {
|
||||||
case Engine::None:
|
case Engine::None:
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
case Engine::GStreamer:
|
case Engine::GStreamer:
|
||||||
engine=true;
|
use_enginetype=Engine::GStreamer;
|
||||||
enginetype=Engine::GStreamer;
|
engine_.reset(new GstEngine(app_->task_manager()));
|
||||||
enginebase = new GstEngine(app_->task_manager());
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_XINE
|
#ifdef HAVE_XINE
|
||||||
case Engine::Xine:
|
case Engine::Xine:
|
||||||
engine=true;
|
use_enginetype=Engine::Xine;
|
||||||
enginetype=Engine::Xine;
|
engine_.reset(new XineEngine(app_->task_manager()));
|
||||||
enginebase = new XineEngine(app_->task_manager());
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_VLC
|
#ifdef HAVE_VLC
|
||||||
case Engine::VLC:
|
case Engine::VLC:
|
||||||
engine=true;
|
use_enginetype=Engine::VLC;
|
||||||
enginetype=Engine::VLC;
|
engine_.reset(new VLCEngine(app_->task_manager()));
|
||||||
enginebase = new VLCEngine(app_->task_manager());
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_PHONON
|
#ifdef HAVE_PHONON
|
||||||
case Engine::Phonon:
|
case Engine::Phonon:
|
||||||
engine=true;
|
use_enginetype=Engine::Phonon;
|
||||||
enginetype=Engine::Phonon;
|
engine_.reset(new PhononEngine(app_->task_manager()));
|
||||||
enginebase = new PhononEngine(app_->task_manager());
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
if (i > 1) { qFatal("No engine available!"); return nullptr; }
|
if (i > 0) { qFatal("No engine available!"); }
|
||||||
QSettings s;
|
enginetype = Engine::None;
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
break;
|
||||||
s.setValue("engine", "");
|
|
||||||
s.setValue("output", "");
|
|
||||||
s.setValue("device", QVariant(""));
|
|
||||||
s.endGroup();
|
|
||||||
enginetype = Engine::None;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QSettings s;
|
if (use_enginetype != enginetype) { // Engine was set to something else. Reset output and device.
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
QSettings s;
|
||||||
s.setValue("engine", Engine::EngineName(enginetype));
|
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||||
s.endGroup();
|
s.setValue("engine", EngineName(use_enginetype));
|
||||||
|
s.setValue("output", engine_->DefaultOutput());
|
||||||
if (enginebase == nullptr) {
|
s.setValue("device", QVariant(""));
|
||||||
qFatal("Failed to create engine!");
|
s.endGroup();
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
engine_.reset(enginebase);
|
if (!engine_) {
|
||||||
|
qFatal("Failed to create engine!");
|
||||||
return enginebase;
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Player::Init() {
|
void Player::Init() {
|
||||||
|
|
||||||
|
if (!engine_->Init()) { qFatal("Error initialising audio engine"); }
|
||||||
|
|
||||||
|
analyzer_->SetEngine(engine_.get());
|
||||||
|
|
||||||
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
connect(engine_.get(), SIGNAL(Error(QString)), SIGNAL(Error(QString)));
|
||||||
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
|
connect(engine_.get(), SIGNAL(ValidSongRequested(QUrl)), SLOT(ValidSongRequested(QUrl)));
|
||||||
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
|
connect(engine_.get(), SIGNAL(InvalidSongRequested(QUrl)), SLOT(InvalidSongRequested(QUrl)));
|
||||||
|
|
||||||
if (!engine_->Init()) qFatal("Error initialising audio engine");
|
|
||||||
|
|
||||||
connect(engine_.get(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
|
connect(engine_.get(), SIGNAL(StateChanged(Engine::State)), SLOT(EngineStateChanged(Engine::State)));
|
||||||
connect(engine_.get(), SIGNAL(TrackAboutToEnd()), SLOT(TrackAboutToEnd()));
|
connect(engine_.get(), SIGNAL(TrackAboutToEnd()), SLOT(TrackAboutToEnd()));
|
||||||
connect(engine_.get(), SIGNAL(TrackEnded()), SLOT(TrackEnded()));
|
connect(engine_.get(), SIGNAL(TrackEnded()), SLOT(TrackEnded()));
|
||||||
connect(engine_.get(), SIGNAL(MetaData(Engine::SimpleMetaBundle)), SLOT(EngineMetadataReceived(Engine::SimpleMetaBundle)));
|
connect(engine_.get(), SIGNAL(MetaData(Engine::SimpleMetaBundle)), SLOT(EngineMetadataReceived(Engine::SimpleMetaBundle)));
|
||||||
|
|
||||||
engine_->SetVolume(settings_.value("volume", 50).toInt());
|
int volume = settings_.value("volume", 50).toInt();
|
||||||
|
engine_->SetVolume(volume);
|
||||||
analyzer_->SetEngine(engine_.get());
|
|
||||||
|
|
||||||
// Equalizer
|
// Equalizer
|
||||||
qLog(Debug) << "Creating equalizer";
|
qLog(Debug) << "Creating equalizer";
|
||||||
@ -195,7 +177,6 @@ void Player::Init() {
|
|||||||
connect(equalizer_, SIGNAL(StereoBalanceChanged(float)), app_->player()->engine(), SLOT(SetStereoBalance(float)));
|
connect(equalizer_, SIGNAL(StereoBalanceChanged(float)), app_->player()->engine(), SLOT(SetStereoBalance(float)));
|
||||||
|
|
||||||
engine_->SetEqualizerEnabled(equalizer_->is_enabled());
|
engine_->SetEqualizerEnabled(equalizer_->is_enabled());
|
||||||
|
|
||||||
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
||||||
engine_->SetStereoBalance(equalizer_->stereo_balance());
|
engine_->SetStereoBalance(equalizer_->stereo_balance());
|
||||||
|
|
||||||
@ -203,15 +184,6 @@ void Player::Init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::SetAnalyzer(AnalyzerContainer *analyzer) {
|
|
||||||
|
|
||||||
analyzer_ = analyzer;
|
|
||||||
|
|
||||||
}
|
|
||||||
void Player::SetEqualizer(Equalizer *equalizer) {
|
|
||||||
equalizer_ = equalizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::ReloadSettings() {
|
void Player::ReloadSettings() {
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
@ -224,7 +196,7 @@ void Player::ReloadSettings() {
|
|||||||
seek_step_sec_ = s.value("seek_step_sec", 10).toInt();
|
seek_step_sec_ = s.value("seek_step_sec", 10).toInt();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
if (engine_.get()) engine_->ReloadSettings();
|
engine_->ReloadSettings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ class Player : public PlayerInterface {
|
|||||||
PreviousBehaviour_Restart = 2
|
PreviousBehaviour_Restart = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
EngineBase *CreateEngine(Engine::EngineType enginetype);
|
void CreateEngine(Engine::EngineType enginetype);
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
EngineBase *engine() const { return engine_.get(); }
|
EngineBase *engine() const { return engine_.get(); }
|
||||||
@ -146,8 +146,8 @@ class Player : public PlayerInterface {
|
|||||||
|
|
||||||
bool PreviousWouldRestartTrack() const;
|
bool PreviousWouldRestartTrack() const;
|
||||||
|
|
||||||
void SetAnalyzer(AnalyzerContainer *analyzer);
|
void SetAnalyzer(AnalyzerContainer *analyzer) { analyzer_ = analyzer; }
|
||||||
void SetEqualizer(Equalizer *equalizer);
|
void SetEqualizer(Equalizer *equalizer) { equalizer_ = equalizer; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
|
||||||
DirectSoundDeviceFinder::DirectSoundDeviceFinder()
|
DirectSoundDeviceFinder::DirectSoundDeviceFinder()
|
||||||
: DeviceFinder("directsound", { "directsound", "dsound", "directsoundsink" }) {
|
: DeviceFinder("directsound", { "directsound", "dsound", "directsoundsink", "directx", "directx2" }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<DeviceFinder::Device> DirectSoundDeviceFinder::ListDevices() {
|
QList<DeviceFinder::Device> DirectSoundDeviceFinder::ListDevices() {
|
||||||
|
@ -84,7 +84,6 @@ bool Engine::Base::Play(const QUrl &url, TrackChangeFlags flags, bool force_stop
|
|||||||
void Engine::Base::SetVolume(uint value) {
|
void Engine::Base::SetVolume(uint value) {
|
||||||
|
|
||||||
volume_ = value;
|
volume_ = value;
|
||||||
|
|
||||||
SetVolumeSW(MakeVolumeLogarithmic(value));
|
SetVolumeSW(MakeVolumeLogarithmic(value));
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -132,3 +131,9 @@ void Engine::Base::EmitAboutToEnd() {
|
|||||||
about_to_end_emitted_ = true;
|
about_to_end_emitted_ = true;
|
||||||
emit TrackAboutToEnd();
|
emit TrackAboutToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Engine::Base::ValidOutput(const QString &output) {
|
||||||
|
|
||||||
|
return (true);
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -89,8 +89,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual OutputDetailsList GetOutputsList() const = 0;
|
virtual OutputDetailsList GetOutputsList() const = 0;
|
||||||
|
virtual bool ValidOutput(const QString &output) = 0;
|
||||||
virtual QString DefaultOutput() = 0;
|
virtual QString DefaultOutput() = 0;
|
||||||
virtual bool CustomDeviceSupport(const QString &name) = 0;
|
virtual bool CustomDeviceSupport(const QString &output) = 0;
|
||||||
|
|
||||||
// Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length).
|
// Plays a media stream represented with the URL 'u' from the given 'beginning' to the given 'end' (usually from 0 to a song's length).
|
||||||
// Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown.
|
// Both markers should be passed in nanoseconds. 'end' can be negative, indicating that the real length of 'u' stream is unknown.
|
||||||
|
@ -99,6 +99,7 @@ GstEngine::GstEngine(TaskManager *task_manager)
|
|||||||
scope_chunk_(0),
|
scope_chunk_(0),
|
||||||
have_new_buffer_(false) {
|
have_new_buffer_(false) {
|
||||||
|
|
||||||
|
type_ = Engine::GStreamer;
|
||||||
seek_timer_->setSingleShot(true);
|
seek_timer_->setSingleShot(true);
|
||||||
seek_timer_->setInterval(kSeekDelayNanosec / kNsecPerMsec);
|
seek_timer_->setInterval(kSeekDelayNanosec / kNsecPerMsec);
|
||||||
connect(seek_timer_, SIGNAL(timeout()), SLOT(SeekNow()));
|
connect(seek_timer_, SIGNAL(timeout()), SLOT(SeekNow()));
|
||||||
@ -129,7 +130,6 @@ bool GstEngine::Init() {
|
|||||||
|
|
||||||
SetEnvironment();
|
SetEnvironment();
|
||||||
|
|
||||||
type_ = Engine::GStreamer;
|
|
||||||
initialising_ = QtConcurrent::run(this, &GstEngine::InitialiseGStreamer);
|
initialising_ = QtConcurrent::run(this, &GstEngine::InitialiseGStreamer);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -388,8 +388,19 @@ EngineBase::OutputDetailsList GstEngine::GetOutputsList() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GstEngine::CustomDeviceSupport(const QString &name) {
|
bool GstEngine::ValidOutput(const QString &output) {
|
||||||
return (name == kALSASink || name == kOpenALSASink || name == kOSSSink || name == kOSS4Sink || name == kPulseSink || name == kA2DPSink || name == kAVDTPSink);
|
|
||||||
|
PluginDetailsList plugins = GetPluginList("Sink/Audio");
|
||||||
|
for (const PluginDetails &plugin : plugins) {
|
||||||
|
if (plugin.name == output) return(true);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GstEngine::CustomDeviceSupport(const QString &output) {
|
||||||
|
return (output == kALSASink || output == kOpenALSASink || output == kOSSSink || output == kOSS4Sink || output == kPulseSink || output == kA2DPSink || output == kAVDTPSink);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEngine::ReloadSettings() {
|
void GstEngine::ReloadSettings() {
|
||||||
|
@ -84,8 +84,9 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
const Engine::Scope &scope(int chunk_length);
|
const Engine::Scope &scope(int chunk_length);
|
||||||
|
|
||||||
OutputDetailsList GetOutputsList() const;
|
OutputDetailsList GetOutputsList() const;
|
||||||
|
bool ValidOutput(const QString &output);
|
||||||
QString DefaultOutput() { return kAutoSink; }
|
QString DefaultOutput() { return kAutoSink; }
|
||||||
bool CustomDeviceSupport(const QString &name);
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
|
||||||
void EnsureInitialised() { initialising_.waitForFinished(); }
|
void EnsureInitialised() { initialising_.waitForFinished(); }
|
||||||
void InitialiseGStreamer();
|
void InitialiseGStreamer();
|
||||||
@ -132,7 +133,6 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
void BufferingFinished();
|
void BufferingFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static const char *kAutoSink;
|
static const char *kAutoSink;
|
||||||
static const char *kALSASink;
|
static const char *kALSASink;
|
||||||
static const char *kOpenALSASink;
|
static const char *kOpenALSASink;
|
||||||
|
@ -32,11 +32,13 @@
|
|||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
|
||||||
PhononEngine::PhononEngine(TaskManager *task_manager)
|
PhononEngine::PhononEngine(TaskManager *task_manager)
|
||||||
: media_object_(new Phonon::MediaObject(this)),
|
: EngineBase(),
|
||||||
|
media_object_(new Phonon::MediaObject(this)),
|
||||||
audio_output_(new Phonon::AudioOutput(Phonon::MusicCategory, this)),
|
audio_output_(new Phonon::AudioOutput(Phonon::MusicCategory, this)),
|
||||||
state_timer_(new QTimer(this)),
|
state_timer_(new QTimer(this)),
|
||||||
seek_offset_(-1)
|
seek_offset_(-1) {
|
||||||
{
|
|
||||||
|
type_ = Engine::Phonon;
|
||||||
|
|
||||||
Phonon::createPath(media_object_, audio_output_);
|
Phonon::createPath(media_object_, audio_output_);
|
||||||
|
|
||||||
@ -54,8 +56,6 @@ PhononEngine::~PhononEngine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PhononEngine::Init() {
|
bool PhononEngine::Init() {
|
||||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
|
||||||
type_ = Engine::Phonon;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +179,13 @@ EngineBase::OutputDetailsList PhononEngine::GetOutputsList() const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhononEngine::CustomDeviceSupport(const QString &name) {
|
bool PhononEngine::ValidOutput(const QString &output) {
|
||||||
|
|
||||||
|
return (output == "auto" || output == "" || output == DefaultOutput);
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PhononEngine::CustomDeviceSupport(const QString &output) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,8 @@ class PhononEngine : public Engine::Base {
|
|||||||
qint64 length_nanosec() const;
|
qint64 length_nanosec() const;
|
||||||
|
|
||||||
QString DefaultOutput() { return ""; }
|
QString DefaultOutput() { return ""; }
|
||||||
bool CustomDeviceSupport(const QString &name);
|
bool ValidOutput(const QString &output);
|
||||||
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetVolumeSW( uint percent );
|
void SetVolumeSW( uint percent );
|
||||||
|
@ -40,13 +40,14 @@
|
|||||||
VLCEngine *VLCEngine::sInstance = nullptr;
|
VLCEngine *VLCEngine::sInstance = nullptr;
|
||||||
|
|
||||||
VLCEngine::VLCEngine(TaskManager *task_manager)
|
VLCEngine::VLCEngine(TaskManager *task_manager)
|
||||||
: instance_(nullptr),
|
: EngineBase(),
|
||||||
|
instance_(nullptr),
|
||||||
player_(nullptr),
|
player_(nullptr),
|
||||||
state_(Engine::Empty),
|
state_(Engine::Empty),
|
||||||
scope_data_(4096)
|
scope_data_(4096) {
|
||||||
{
|
|
||||||
|
|
||||||
Init();
|
type_ = Engine::VLC;
|
||||||
|
ReloadSettings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,8 +62,6 @@ VLCEngine::~VLCEngine() {
|
|||||||
|
|
||||||
bool VLCEngine::Init() {
|
bool VLCEngine::Init() {
|
||||||
|
|
||||||
type_ = Engine::VLC;
|
|
||||||
|
|
||||||
/* FIXME: Do we need this?
|
/* FIXME: Do we need this?
|
||||||
static const char *const args[] = {
|
static const char *const args[] = {
|
||||||
"-I", "dummy", // Don't use any interface
|
"-I", "dummy", // Don't use any interface
|
||||||
@ -113,8 +112,15 @@ bool VLCEngine::Init() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VLCEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
bool VLCEngine::Initialised() const {
|
||||||
|
|
||||||
|
if (instance_ && player_) return true;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VLCEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||||
|
if (!Initialised()) return false;
|
||||||
// Create the media object
|
// Create the media object
|
||||||
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, url.toEncoded().constData()));
|
VlcScopedRef<libvlc_media_t> media(libvlc_media_new_location(instance_, url.toEncoded().constData()));
|
||||||
|
|
||||||
@ -125,7 +131,7 @@ bool VLCEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool forc
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool VLCEngine::Play(quint64 offset_nanosec) {
|
bool VLCEngine::Play(quint64 offset_nanosec) {
|
||||||
|
if (!Initialised()) return false;
|
||||||
// Set audio output
|
// Set audio output
|
||||||
if (!output_.isEmpty() || output_ != "auto") {
|
if (!output_.isEmpty() || output_ != "auto") {
|
||||||
int result = libvlc_audio_output_set(player_, output_.toUtf8().constData());
|
int result = libvlc_audio_output_set(player_, output_.toUtf8().constData());
|
||||||
@ -148,21 +154,21 @@ bool VLCEngine::Play(quint64 offset_nanosec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VLCEngine::Stop(bool stop_after) {
|
void VLCEngine::Stop(bool stop_after) {
|
||||||
|
if (!Initialised()) return;
|
||||||
libvlc_media_player_stop(player_);
|
libvlc_media_player_stop(player_);
|
||||||
HandleErrors();
|
HandleErrors();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLCEngine::Pause() {
|
void VLCEngine::Pause() {
|
||||||
|
if (!Initialised()) return;
|
||||||
libvlc_media_player_pause(player_);
|
libvlc_media_player_pause(player_);
|
||||||
HandleErrors();
|
HandleErrors();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLCEngine::Unpause() {
|
void VLCEngine::Unpause() {
|
||||||
|
if (!Initialised()) return;
|
||||||
libvlc_media_player_play(player_);
|
libvlc_media_player_play(player_);
|
||||||
HandleErrors();
|
HandleErrors();
|
||||||
|
|
||||||
@ -170,6 +176,8 @@ void VLCEngine::Unpause() {
|
|||||||
|
|
||||||
void VLCEngine::Seek(quint64 offset_nanosec) {
|
void VLCEngine::Seek(quint64 offset_nanosec) {
|
||||||
|
|
||||||
|
if (!Initialised()) return;
|
||||||
|
|
||||||
int offset = (offset_nanosec / kNsecPerMsec);
|
int offset = (offset_nanosec / kNsecPerMsec);
|
||||||
|
|
||||||
uint len = length();
|
uint len = length();
|
||||||
@ -183,7 +191,7 @@ void VLCEngine::Seek(quint64 offset_nanosec) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VLCEngine::SetVolumeSW(uint percent) {
|
void VLCEngine::SetVolumeSW(uint percent) {
|
||||||
|
if (!Initialised()) return;
|
||||||
libvlc_audio_set_volume(player_, percent);
|
libvlc_audio_set_volume(player_, percent);
|
||||||
HandleErrors();
|
HandleErrors();
|
||||||
}
|
}
|
||||||
@ -248,12 +256,24 @@ EngineBase::OutputDetailsList VLCEngine::GetOutputsList() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VLCEngine::CustomDeviceSupport(const QString &name) {
|
bool VLCEngine::ValidOutput(const QString &output) {
|
||||||
return (name == "auto" ? false : true);
|
|
||||||
|
PluginDetailsList plugins = GetPluginList();
|
||||||
|
for (const PluginDetails &plugin : plugins) {
|
||||||
|
if (plugin.name == output) return(true);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VLCEngine::CustomDeviceSupport(const QString &output) {
|
||||||
|
return (output == "auto" ? false : true);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint VLCEngine::position() const {
|
uint VLCEngine::position() const {
|
||||||
|
|
||||||
|
if (!Initialised()) return (0);
|
||||||
|
|
||||||
bool is_playing = libvlc_media_player_is_playing(player_);
|
bool is_playing = libvlc_media_player_is_playing(player_);
|
||||||
HandleErrors();
|
HandleErrors();
|
||||||
|
|
||||||
@ -268,6 +288,8 @@ uint VLCEngine::position() const {
|
|||||||
|
|
||||||
uint VLCEngine::length() const {
|
uint VLCEngine::length() const {
|
||||||
|
|
||||||
|
if (!Initialised()) return(0);
|
||||||
|
|
||||||
bool is_playing = libvlc_media_player_is_playing(player_);
|
bool is_playing = libvlc_media_player_is_playing(player_);
|
||||||
HandleErrors();
|
HandleErrors();
|
||||||
|
|
||||||
|
@ -63,8 +63,9 @@ class VLCEngine : public Engine::Base {
|
|||||||
const Engine::Scope& Scope();
|
const Engine::Scope& Scope();
|
||||||
|
|
||||||
OutputDetailsList GetOutputsList() const;
|
OutputDetailsList GetOutputsList() const;
|
||||||
|
bool ValidOutput(const QString &output);
|
||||||
QString DefaultOutput() { return ""; }
|
QString DefaultOutput() { return ""; }
|
||||||
bool CustomDeviceSupport(const QString &name);
|
bool CustomDeviceSupport(const QString &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
libvlc_instance_t *instance_;
|
libvlc_instance_t *instance_;
|
||||||
@ -75,6 +76,7 @@ class VLCEngine : public Engine::Base {
|
|||||||
static VLCEngine *sInstance;
|
static VLCEngine *sInstance;
|
||||||
QMutex scope_mutex_;
|
QMutex scope_mutex_;
|
||||||
|
|
||||||
|
bool Initialised() const;
|
||||||
uint position() const;
|
uint position() const;
|
||||||
uint length() const;
|
uint length() const;
|
||||||
bool CanDecode(const QUrl &url);
|
bool CanDecode(const QUrl &url);
|
||||||
|
@ -65,12 +65,8 @@ using std::shared_ptr;
|
|||||||
#define LLONG_MAX 9223372036854775807LL
|
#define LLONG_MAX 9223372036854775807LL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Define this to use xine in a more standard way
|
||||||
//define this to use xine in a more standard way
|
|
||||||
//#ifdef Q_OS_WIN32
|
|
||||||
//#define XINE_SAFE_MODE
|
//#define XINE_SAFE_MODE
|
||||||
//#endif
|
|
||||||
|
|
||||||
|
|
||||||
const char *XineEngine::kAutoOutput = "auto";
|
const char *XineEngine::kAutoOutput = "auto";
|
||||||
int XineEngine::last_error_ = XINE_MSG_NO_ERROR;
|
int XineEngine::last_error_ = XINE_MSG_NO_ERROR;
|
||||||
@ -88,56 +84,28 @@ XineEngine::XineEngine(TaskManager *task_manager)
|
|||||||
fadeout_running_ (false),
|
fadeout_running_ (false),
|
||||||
prune_(nullptr) {
|
prune_(nullptr) {
|
||||||
|
|
||||||
|
type_ = Engine::Xine;
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XineEngine::~XineEngine() {
|
XineEngine::~XineEngine() {
|
||||||
|
|
||||||
// Wait until the fader thread is done
|
|
||||||
if (s_fader_) {
|
|
||||||
stop_fader_ = true;
|
|
||||||
s_fader_->resume(); // safety call if the engine is in the pause state
|
|
||||||
s_fader_->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait until the prune scope thread is done
|
|
||||||
if (prune_) {
|
|
||||||
prune_->exit();
|
|
||||||
prune_->wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
s_fader_.reset();
|
|
||||||
s_outfader_.reset();
|
|
||||||
prune_.reset();
|
|
||||||
|
|
||||||
if (fadeout_enabled_) {
|
if (fadeout_enabled_) {
|
||||||
bool terminateFader = false;
|
bool terminateFader = false;
|
||||||
FadeOut(fadeout_duration_, &terminateFader, true); // true == exiting
|
FadeOut(fadeout_duration_, &terminateFader, true); // true == exiting
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream_) xine_close(stream_);
|
Cleanup();
|
||||||
if (eventqueue_) xine_event_dispose_queue(eventqueue_);
|
|
||||||
if (stream_) xine_dispose(stream_);
|
|
||||||
if (audioport_) xine_close_audio_driver(xine_, audioport_);
|
|
||||||
if (post_) xine_post_dispose(xine_, post_);
|
|
||||||
if (xine_) xine_exit(xine_);
|
|
||||||
|
|
||||||
//qLog(Debug) << "xine closed";
|
|
||||||
//qLog(Debug) << "Scope statistics:";
|
|
||||||
//qLog(Debug) << "Average list size: " << log_buffer_count_ / log_scope_call_count_;
|
|
||||||
//qLog(Debug) << "Buffer failure: " << double(log_no_suitable_buffer_*100) / log_scope_call_count_ << "%";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XineEngine::Init() {
|
bool XineEngine::Init() {
|
||||||
|
|
||||||
type_ = Engine::Xine;
|
Cleanup();
|
||||||
|
|
||||||
SetEnvironment();
|
SetEnvironment();
|
||||||
|
|
||||||
QMutexLocker l(&init_mutex_);
|
QMutexLocker l(&init_mutex_);
|
||||||
|
|
||||||
xine_ = xine_new();
|
xine_ = xine_new();
|
||||||
if (!xine_) {
|
if (!xine_) {
|
||||||
emit Error("Could not initialize xine.");
|
emit Error("Could not initialize xine.");
|
||||||
@ -150,14 +118,73 @@ bool XineEngine::Init() {
|
|||||||
|
|
||||||
xine_init(xine_);
|
xine_init(xine_);
|
||||||
|
|
||||||
MakeNewStream();
|
|
||||||
|
|
||||||
#ifndef XINE_SAFE_MODE
|
#ifndef XINE_SAFE_MODE
|
||||||
prune_.reset(new PruneScopeThread(this));
|
prune_.reset(new PruneScopeThread(this));
|
||||||
prune_->start();
|
prune_->start();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
SetDevice();
|
||||||
|
|
||||||
|
if (!ValidOutput(output_)) {
|
||||||
|
qLog(Error) << "Invalid output detected:" << output_ << " - Resetting to default.";
|
||||||
|
output_ = DefaultOutput();
|
||||||
|
}
|
||||||
|
audioport_ = xine_open_audio_driver(xine_, (output_.isEmpty() || output_ == kAutoOutput ? nullptr : output_.toUtf8().constData()), nullptr);
|
||||||
|
if (!audioport_) {
|
||||||
|
emit Error("Xine was unable to initialize any audio drivers.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void XineEngine::Cleanup() {
|
||||||
|
|
||||||
|
// Wait until the prune scope thread is done
|
||||||
|
if (prune_) {
|
||||||
|
prune_->exit();
|
||||||
|
prune_->wait();
|
||||||
|
}
|
||||||
|
prune_.reset();
|
||||||
|
|
||||||
|
// Wait until the fader thread is done
|
||||||
|
if (s_fader_) {
|
||||||
|
stop_fader_ = true;
|
||||||
|
s_fader_->resume(); // safety call if the engine is in the pause state
|
||||||
|
s_fader_->wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
s_fader_.reset();
|
||||||
|
s_outfader_.reset();
|
||||||
|
|
||||||
|
if (stream_)
|
||||||
|
xine_close(stream_);
|
||||||
|
if (eventqueue_) {
|
||||||
|
xine_event_dispose_queue(eventqueue_);
|
||||||
|
eventqueue_ = nullptr;
|
||||||
|
}
|
||||||
|
if (stream_) {
|
||||||
|
xine_dispose(stream_);
|
||||||
|
stream_ = nullptr;
|
||||||
|
}
|
||||||
|
if (audioport_) {
|
||||||
|
xine_close_audio_driver(xine_, audioport_);
|
||||||
|
audioport_ = nullptr;
|
||||||
|
}
|
||||||
|
if (post_) {
|
||||||
|
xine_post_dispose(xine_, post_);
|
||||||
|
post_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xine_) xine_exit(xine_);
|
||||||
|
xine_ = nullptr;
|
||||||
|
|
||||||
|
//qLog(Debug) << "xine closed";
|
||||||
|
//qLog(Debug) << "Scope statistics:";
|
||||||
|
//qLog(Debug) << "Average list size: " << log_buffer_count_ / log_scope_call_count_;
|
||||||
|
//qLog(Debug) << "Buffer failure: " << double(log_no_suitable_buffer_*100) / log_scope_call_count_ << "%";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Engine::State XineEngine::state() const {
|
Engine::State XineEngine::state() const {
|
||||||
@ -183,7 +210,7 @@ bool XineEngine::Load(const QUrl &url, Engine::TrackChangeFlags change, bool for
|
|||||||
|
|
||||||
if (s_outfader_) {
|
if (s_outfader_) {
|
||||||
s_outfader_->finish();
|
s_outfader_->finish();
|
||||||
if (s_outfader_) s_outfader_.reset();
|
s_outfader_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fade_length_ > 0 && xine_get_status(stream_) == XINE_STATUS_PLAY && url.scheme().toLower() == "file" && xine_get_param(stream_, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE && (fade_next_track_ || crossfade_enabled_)) {
|
if (fade_length_ > 0 && xine_get_status(stream_) == XINE_STATUS_PLAY && url.scheme().toLower() == "file" && xine_get_param(stream_, XINE_PARAM_SPEED) != XINE_SPEED_PAUSE && (fade_next_track_ || crossfade_enabled_)) {
|
||||||
@ -370,14 +397,22 @@ EngineBase::OutputDetailsList XineEngine::GetOutputsList() const {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XineEngine::CustomDeviceSupport(const QString &name) {
|
bool XineEngine::ValidOutput(const QString &output) {
|
||||||
return (name == "alsa" || name == "oss" || name == "jack" || name == "pulseaudio");
|
|
||||||
|
PluginDetailsList plugins = GetPluginList();
|
||||||
|
for (const PluginDetails &plugin : plugins) {
|
||||||
|
if (plugin.name == output) return(true);
|
||||||
|
}
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XineEngine::CustomDeviceSupport(const QString &output) {
|
||||||
|
return (output == "alsa" || output == "oss" || output == "jack" || output == "pulseaudio");
|
||||||
}
|
}
|
||||||
|
|
||||||
void XineEngine::ReloadSettings() {
|
void XineEngine::ReloadSettings() {
|
||||||
|
|
||||||
QSettings s;
|
|
||||||
|
|
||||||
Engine::Base::ReloadSettings();
|
Engine::Base::ReloadSettings();
|
||||||
|
|
||||||
if (output_ == "") output_ = DefaultOutput();
|
if (output_ == "") output_ = DefaultOutput();
|
||||||
@ -386,13 +421,13 @@ void XineEngine::ReloadSettings() {
|
|||||||
|
|
||||||
void XineEngine::SetEnvironment() {
|
void XineEngine::SetEnvironment() {
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN
|
||||||
putenv(QString("XINE_PLUGIN_PATH=" + QCoreApplication::applicationDirPath() + "/xine/plugins").toLatin1().constData());
|
putenv(QString("XINE_PLUGIN_PATH=" + QCoreApplication::applicationDirPath() + "/xine-plugins").toLatin1().constData());
|
||||||
#endif // Q_OS_WIN32
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
setenv("XINE_PLUGIN_PATH", QString(QCoreApplication::applicationDirPath() + "/../PlugIns/xine").toLatin1().constData(), 1);
|
setenv("XINE_PLUGIN_PATH", QString(QCoreApplication::applicationDirPath() + "/../PlugIns/xine").toLatin1().constData(), 1);
|
||||||
#endif // Q_OS_DARWIN
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,7 +903,7 @@ Engine::SimpleMetaBundle XineEngine::fetchMetaData() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool XineEngine::MakeNewStream() {
|
void XineEngine::SetDevice() {
|
||||||
|
|
||||||
if (device_.isValid()) {
|
if (device_.isValid()) {
|
||||||
bool valid(false);
|
bool valid(false);
|
||||||
@ -892,12 +927,11 @@ bool XineEngine::MakeNewStream() {
|
|||||||
xine_config_update_entry(xine_, &entry);
|
xine_config_update_entry(xine_, &entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
current_device_ = device_;
|
||||||
|
|
||||||
audioport_ = xine_open_audio_driver(xine_, (output_.isEmpty() || output_ == kAutoOutput ? nullptr : output_.toUtf8().constData()), nullptr);
|
}
|
||||||
if (!audioport_) {
|
|
||||||
emit Error("Xine was unable to initialize any audio drivers.");
|
bool XineEngine::CreateStream() {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream_ = xine_stream_new(xine_, audioport_, nullptr);
|
stream_ = xine_stream_new(xine_, audioport_, nullptr);
|
||||||
if (!stream_) {
|
if (!stream_) {
|
||||||
@ -908,7 +942,6 @@ bool XineEngine::MakeNewStream() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (eventqueue_) xine_event_dispose_queue(eventqueue_);
|
if (eventqueue_) xine_event_dispose_queue(eventqueue_);
|
||||||
|
|
||||||
eventqueue_ = xine_event_new_queue(stream_);
|
eventqueue_ = xine_event_new_queue(stream_);
|
||||||
xine_event_create_listener_thread(eventqueue_, &XineEngine::XineEventListener, (void*)this);
|
xine_event_create_listener_thread(eventqueue_, &XineEngine::XineEventListener, (void*)this);
|
||||||
|
|
||||||
@ -923,7 +956,7 @@ bool XineEngine::MakeNewStream() {
|
|||||||
if (xine_check_version(1, 1, 1) && !(fade_length_ > 0)) {
|
if (xine_check_version(1, 1, 1) && !(fade_length_ > 0)) {
|
||||||
// Enable gapless playback
|
// Enable gapless playback
|
||||||
qLog(Debug) << "gapless playback enabled.";
|
qLog(Debug) << "gapless playback enabled.";
|
||||||
// xine_set_param(stream_, XINE_PARAM_EARLY_FINISHED_EVENT, 1);
|
xine_set_param(stream_, XINE_PARAM_EARLY_FINISHED_EVENT, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
@ -931,7 +964,7 @@ bool XineEngine::MakeNewStream() {
|
|||||||
|
|
||||||
bool XineEngine::EnsureStream() {
|
bool XineEngine::EnsureStream() {
|
||||||
|
|
||||||
if (!stream_) return MakeNewStream();
|
if (!stream_) return CreateStream();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,7 @@ private:
|
|||||||
class XineEngine : public Engine::Base {
|
class XineEngine : public Engine::Base {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
XineEngine(TaskManager *task_manager);
|
XineEngine(TaskManager *task_manager);
|
||||||
~XineEngine();
|
~XineEngine();
|
||||||
|
|
||||||
@ -86,38 +85,21 @@ public:
|
|||||||
|
|
||||||
const Engine::Scope& scope(int chunk_length);
|
const Engine::Scope& scope(int chunk_length);
|
||||||
|
|
||||||
QString DefaultOutput() { return "auto"; }
|
|
||||||
OutputDetailsList GetOutputsList() const;
|
OutputDetailsList GetOutputsList() const;
|
||||||
bool CustomDeviceSupport(const QString &name);
|
bool ValidOutput(const QString &output);
|
||||||
|
QString DefaultOutput() { return "auto"; }
|
||||||
|
bool CustomDeviceSupport(const QString &output);
|
||||||
|
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|
||||||
void SetEnvironment();
|
|
||||||
|
|
||||||
uint length() const;
|
|
||||||
uint position() const;
|
|
||||||
|
|
||||||
bool CanDecode(const QUrl &);
|
bool CanDecode(const QUrl &);
|
||||||
|
bool CreateStream();
|
||||||
bool MetaDataForUrl(const QUrl &url, Engine::SimpleMetaBundle &b);
|
|
||||||
bool GetAudioCDContents(const QString &device, QList<QUrl> &urls);
|
|
||||||
bool FlushBuffer();
|
|
||||||
|
|
||||||
void SetEqualizerEnabled(bool enabled);
|
void SetEqualizerEnabled(bool enabled);
|
||||||
void SetEqualizerParameters(int preamp, const QList<int>&);
|
void SetEqualizerParameters(int preamp, const QList<int>&);
|
||||||
|
|
||||||
void FadeOut(uint fadeLength, bool* terminate, bool exiting = false);
|
void FadeOut(uint fadeLength, bool* terminate, bool exiting = false);
|
||||||
|
|
||||||
static void XineEventListener(void*, const xine_event_t*);
|
|
||||||
bool event(QEvent*);
|
|
||||||
|
|
||||||
Engine::SimpleMetaBundle fetchMetaData() const;
|
|
||||||
|
|
||||||
bool MakeNewStream();
|
|
||||||
bool EnsureStream();
|
|
||||||
|
|
||||||
void DetermineAndShowErrorMessage(); //call after failure to load/play
|
|
||||||
|
|
||||||
// Simple accessors
|
// Simple accessors
|
||||||
|
|
||||||
xine_stream_t *stream() { return stream_; }
|
xine_stream_t *stream() { return stream_; }
|
||||||
@ -125,10 +107,12 @@ public:
|
|||||||
bool stop_fader() { return stop_fader_; }
|
bool stop_fader() { return stop_fader_; }
|
||||||
void set_stop_fader(bool stop_fader) { stop_fader_ = stop_fader; }
|
void set_stop_fader(bool stop_fader) { stop_fader_ = stop_fader; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static const char *kAutoOutput;
|
static const char *kAutoOutput;
|
||||||
|
|
||||||
|
QString current_output_;
|
||||||
|
QVariant current_device_;
|
||||||
|
|
||||||
xine_t *xine_;
|
xine_t *xine_;
|
||||||
xine_stream_t *stream_;
|
xine_stream_t *stream_;
|
||||||
xine_audio_port_t *audioport_;
|
xine_audio_port_t *audioport_;
|
||||||
@ -160,6 +144,26 @@ private:
|
|||||||
|
|
||||||
mutable Engine::SimpleMetaBundle current_bundle_;
|
mutable Engine::SimpleMetaBundle current_bundle_;
|
||||||
|
|
||||||
|
void SetEnvironment();
|
||||||
|
|
||||||
|
void Cleanup();
|
||||||
|
bool EnsureStream();
|
||||||
|
void SetDevice();
|
||||||
|
|
||||||
|
uint length() const;
|
||||||
|
uint position() const;
|
||||||
|
|
||||||
|
bool MetaDataForUrl(const QUrl &url, Engine::SimpleMetaBundle &b);
|
||||||
|
bool GetAudioCDContents(const QString &device, QList<QUrl> &urls);
|
||||||
|
bool FlushBuffer();
|
||||||
|
|
||||||
|
static void XineEventListener(void*, const xine_event_t*);
|
||||||
|
bool event(QEvent*);
|
||||||
|
|
||||||
|
Engine::SimpleMetaBundle fetchMetaData() const;
|
||||||
|
|
||||||
|
void DetermineAndShowErrorMessage(); //call after failure to load/play
|
||||||
|
|
||||||
PluginDetailsList GetPluginList() const;
|
PluginDetailsList GetPluginList() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -38,7 +38,7 @@ XineFader::XineFader(XineEngine *engine, xine_t *xine, xine_stream_t *stream, xi
|
|||||||
paused_(false),
|
paused_(false),
|
||||||
terminated_(false) {
|
terminated_(false) {
|
||||||
|
|
||||||
if (engine->MakeNewStream()) {
|
if (engine->CreateStream()) {
|
||||||
increase_ = stream_;
|
increase_ = stream_;
|
||||||
xine_set_param(increase_, XINE_PARAM_AUDIO_AMP_LEVEL, 0);
|
xine_set_param(increase_, XINE_PARAM_AUDIO_AMP_LEVEL, 0);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,10 @@
|
|||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
#include "core/signalchecker.h"
|
#include "core/signalchecker.h"
|
||||||
|
|
||||||
|
#ifndef u_int32_t
|
||||||
|
typedef unsigned int u_int32_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const int kDecodeRate = 11025;
|
static const int kDecodeRate = 11025;
|
||||||
static const int kDecodeChannels = 1;
|
static const int kDecodeChannels = 1;
|
||||||
static const int kPlayLengthSecs = 30;
|
static const int kPlayLengthSecs = 30;
|
||||||
|
@ -79,7 +79,8 @@ void BackendSettingsPage::Load() {
|
|||||||
engineloaded_ = false;
|
engineloaded_ = false;
|
||||||
xinewarning_ = false;
|
xinewarning_ = false;
|
||||||
|
|
||||||
Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineDescription(Engine::GStreamer)).toString());
|
Engine::EngineType enginetype = Engine::EngineTypeFromName(s_.value("engine", EngineName(Engine::None)).toString());
|
||||||
|
if (enginetype == Engine::None && engine()) enginetype = engine()->type();
|
||||||
|
|
||||||
ui_->combobox_engine->clear();
|
ui_->combobox_engine->clear();
|
||||||
#ifdef HAVE_GSTREAMER
|
#ifdef HAVE_GSTREAMER
|
||||||
@ -95,7 +96,9 @@ void BackendSettingsPage::Load() {
|
|||||||
ui_->combobox_engine->addItem(IconLoader::Load("speaker"), EngineDescription(Engine::Phonon), Engine::Phonon);
|
ui_->combobox_engine->addItem(IconLoader::Load("speaker"), EngineDescription(Engine::Phonon), Engine::Phonon);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enginereset_ = false;
|
enginetype_current_ = enginetype;
|
||||||
|
output_current_ = s_.value("output", "").toString();
|
||||||
|
device_current_ = s_.value("device", QVariant());
|
||||||
|
|
||||||
ui_->combobox_engine->setCurrentIndex(ui_->combobox_engine->findData(enginetype));
|
ui_->combobox_engine->setCurrentIndex(ui_->combobox_engine->findData(enginetype));
|
||||||
if (EngineInitialised()) Load_Engine(enginetype);
|
if (EngineInitialised()) Load_Engine(enginetype);
|
||||||
@ -152,8 +155,8 @@ void BackendSettingsPage::Load_Engine(Engine::EngineType enginetype) {
|
|||||||
|
|
||||||
if (!EngineInitialised()) return;
|
if (!EngineInitialised()) return;
|
||||||
|
|
||||||
QString output = s_.value("output", "").toString();
|
QString output = output_current_;
|
||||||
QVariant device = s_.value("device", QVariant());
|
QVariant device = device_current_;
|
||||||
|
|
||||||
ui_->combobox_output->clear();
|
ui_->combobox_output->clear();
|
||||||
ui_->combobox_device->clear();
|
ui_->combobox_device->clear();
|
||||||
@ -167,9 +170,11 @@ void BackendSettingsPage::Load_Engine(Engine::EngineType enginetype) {
|
|||||||
ui_->groupbox_replaygain->setEnabled(false);
|
ui_->groupbox_replaygain->setEnabled(false);
|
||||||
|
|
||||||
if (engine()->type() != enginetype) {
|
if (engine()->type() != enginetype) {
|
||||||
|
qLog(Debug) << "Switching engine.";
|
||||||
dialog()->app()->player()->CreateEngine(enginetype);
|
dialog()->app()->player()->CreateEngine(enginetype);
|
||||||
dialog()->app()->player()->ReloadSettings();
|
dialog()->app()->player()->ReloadSettings();
|
||||||
dialog()->app()->player()->Init();
|
dialog()->app()->player()->Init();
|
||||||
|
dialog()->set_output_changed(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
engineloaded_ = true;
|
engineloaded_ = true;
|
||||||
@ -203,6 +208,7 @@ void BackendSettingsPage::Load_Output(QString output, QVariant device) {
|
|||||||
}
|
}
|
||||||
if (!found) { // Output is invalid for this engine, reset to default output.
|
if (!found) { // Output is invalid for this engine, reset to default output.
|
||||||
output = engine()->DefaultOutput();
|
output = engine()->DefaultOutput();
|
||||||
|
device = (engine()->CustomDeviceSupport(output) == true ? QVariant("") : QVariant());
|
||||||
for (int i = 0; i < ui_->combobox_output->count(); ++i) {
|
for (int i = 0; i < ui_->combobox_output->count(); ++i) {
|
||||||
EngineBase::OutputDetails o = ui_->combobox_output->itemData(i).value<EngineBase::OutputDetails>();
|
EngineBase::OutputDetails o = ui_->combobox_output->itemData(i).value<EngineBase::OutputDetails>();
|
||||||
if (o.name == output) {
|
if (o.name == output) {
|
||||||
@ -212,8 +218,16 @@ void BackendSettingsPage::Load_Output(QString output, QVariant device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine()->type() == Engine::GStreamer) ui_->groupbox_replaygain->setEnabled(true);
|
if (engine()->type() == Engine::GStreamer) {
|
||||||
else ui_->groupbox_replaygain->setEnabled(false);
|
ui_->groupbox_buffer->setEnabled(true);
|
||||||
|
ui_->groupbox_replaygain->setEnabled(true);
|
||||||
|
ui_->checkbox_monoplayback->setEnabled(true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ui_->groupbox_buffer->setEnabled(false);
|
||||||
|
ui_->groupbox_replaygain->setEnabled(false);
|
||||||
|
ui_->checkbox_monoplayback->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (ui_->combobox_output->count() < 1) {
|
if (ui_->combobox_output->count() < 1) {
|
||||||
ShowWarning("Engine may take some time to initialize. Close settings and reopen to set output and devices.");
|
ShowWarning("Engine may take some time to initialize. Close settings and reopen to set output and devices.");
|
||||||
@ -315,23 +329,35 @@ void BackendSettingsPage::Save() {
|
|||||||
s_.setValue("rgpreamp", float(ui_->stickslider_replaygainpreamp->value()) / 10 - 15);
|
s_.setValue("rgpreamp", float(ui_->stickslider_replaygainpreamp->value()) / 10 - 15);
|
||||||
s_.setValue("rgcompression", ui_->checkbox_replaygaincompression->isChecked());
|
s_.setValue("rgcompression", ui_->checkbox_replaygaincompression->isChecked());
|
||||||
|
|
||||||
|
// If engine has not been changed, but output or device has been changed,
|
||||||
|
// then set_output_changed(true) to reinitialize engine when dialog closes.
|
||||||
|
if (enginetype == enginetype_current_ && (output_name != output_current_ || device_value != device_current_)) dialog()->set_output_changed(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendSettingsPage::Cancel() {
|
||||||
|
if (engine() && engine()->type() != enginetype_current_) { // Reset engine back to the original because user cancelled.
|
||||||
|
dialog()->app()->player()->CreateEngine(enginetype_current_);
|
||||||
|
dialog()->app()->player()->ReloadSettings();
|
||||||
|
dialog()->app()->player()->Init();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendSettingsPage::EngineChanged(int index) {
|
void BackendSettingsPage::EngineChanged(int index) {
|
||||||
|
|
||||||
if (!configloaded_ || !EngineInitialised()) return;
|
if (!configloaded_ || !EngineInitialised()) return;
|
||||||
|
|
||||||
if (engine()->state() != Engine::Empty) {
|
|
||||||
if (enginereset_ == true) { enginereset_ = false; return; }
|
|
||||||
errordialog_.ShowMessage("Can't switch engine while playing!");
|
|
||||||
enginereset_ = true;
|
|
||||||
ui_->combobox_engine->setCurrentIndex(ui_->combobox_engine->findData(engineloaded_));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant v = ui_->combobox_engine->itemData(index);
|
QVariant v = ui_->combobox_engine->itemData(index);
|
||||||
Engine::EngineType enginetype = v.value<Engine::EngineType>();
|
Engine::EngineType enginetype = v.value<Engine::EngineType>();
|
||||||
|
|
||||||
|
if (engine()->type() == enginetype) return;
|
||||||
|
|
||||||
|
if (engine()->state() != Engine::Empty) {
|
||||||
|
errordialog_.ShowMessage("Can't switch engine while playing!");
|
||||||
|
ui_->combobox_engine->setCurrentIndex(ui_->combobox_engine->findData(engine()->type()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
engineloaded_ = false;
|
engineloaded_ = false;
|
||||||
xinewarning_ = false;
|
xinewarning_ = false;
|
||||||
ResetWarning();
|
ResetWarning();
|
||||||
@ -346,7 +372,7 @@ void BackendSettingsPage::OutputChanged(int index) {
|
|||||||
EngineBase::OutputDetails output = ui_->combobox_output->itemData(index).value<EngineBase::OutputDetails>();
|
EngineBase::OutputDetails output = ui_->combobox_output->itemData(index).value<EngineBase::OutputDetails>();
|
||||||
Load_Device(output.name, QVariant());
|
Load_Device(output.name, QVariant());
|
||||||
|
|
||||||
if (engine()->type() == Engine::Xine) XineWarning();
|
if (engine()->type() == Engine::Xine && engine()->state() != Engine::Empty) XineWarning();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +397,7 @@ void BackendSettingsPage::DeviceSelectionChanged(int index) {
|
|||||||
if (!ui_->lineedit_device->text().isEmpty()) ui_->lineedit_device->setText("");
|
if (!ui_->lineedit_device->text().isEmpty()) ui_->lineedit_device->setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine()->type() == Engine::Xine) XineWarning();
|
if (engine()->type() == Engine::Xine && engine()->state() != Engine::Empty) XineWarning();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,8 +493,8 @@ void BackendSettingsPage::XineWarning() {
|
|||||||
|
|
||||||
if (!engineloaded_) return;
|
if (!engineloaded_) return;
|
||||||
if (!configloaded_) return;
|
if (!configloaded_) return;
|
||||||
|
|
||||||
if (engine()->type() != Engine::Xine) return;
|
if (engine()->type() != Engine::Xine) return;
|
||||||
|
if (engine()->state() == Engine::Empty) return;
|
||||||
if (xinewarning_) return;
|
if (xinewarning_) return;
|
||||||
|
|
||||||
ShowWarning("You need to restart Strawberry for output/device changes to take affect for Xine.");
|
ShowWarning("You need to restart Strawberry for output/device changes to take affect for Xine.");
|
||||||
|
@ -52,6 +52,7 @@ public:
|
|||||||
|
|
||||||
void Load();
|
void Load();
|
||||||
void Save();
|
void Save();
|
||||||
|
void Cancel();
|
||||||
|
|
||||||
EngineBase *engine() const { return dialog()->app()->player()->engine(); }
|
EngineBase *engine() const { return dialog()->app()->player()->engine(); }
|
||||||
|
|
||||||
@ -81,9 +82,12 @@ private:
|
|||||||
QSettings s_;
|
QSettings s_;
|
||||||
bool configloaded_;
|
bool configloaded_;
|
||||||
bool engineloaded_;
|
bool engineloaded_;
|
||||||
ErrorDialog errordialog_;
|
|
||||||
bool enginereset_;
|
|
||||||
bool xinewarning_;
|
bool xinewarning_;
|
||||||
|
ErrorDialog errordialog_;
|
||||||
|
|
||||||
|
Engine::EngineType enginetype_current_;
|
||||||
|
QString output_current_;
|
||||||
|
QVariant device_current_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
|
|
||||||
#include "core/iconloader.h"
|
#include "core/iconloader.h"
|
||||||
|
#include "core/logging.h"
|
||||||
#include "settingspage.h"
|
#include "settingspage.h"
|
||||||
#include "playbacksettingspage.h"
|
#include "playbacksettingspage.h"
|
||||||
#include "ui_playbacksettingspage.h"
|
#include "ui_playbacksettingspage.h"
|
||||||
@ -50,9 +51,7 @@ PlaybackSettingsPage::PlaybackSettingsPage(SettingsDialog *dialog) : SettingsPag
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlaybackSettingsPage::~PlaybackSettingsPage() {
|
PlaybackSettingsPage::~PlaybackSettingsPage() {
|
||||||
|
|
||||||
delete ui_;
|
delete ui_;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackSettingsPage::Load() {
|
void PlaybackSettingsPage::Load() {
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "core/player.h"
|
#include "core/player.h"
|
||||||
|
#include "core/logging.h"
|
||||||
#include "engine/enginebase.h"
|
#include "engine/enginebase.h"
|
||||||
#include "widgets/groupediconview.h"
|
#include "widgets/groupediconview.h"
|
||||||
#include "collection/collectionmodel.h"
|
#include "collection/collectionmodel.h"
|
||||||
@ -104,7 +105,8 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
|
|||||||
model_(app_->collection_model()->directory_model()),
|
model_(app_->collection_model()->directory_model()),
|
||||||
appearance_(app_->appearance()),
|
appearance_(app_->appearance()),
|
||||||
ui_(new Ui_SettingsDialog),
|
ui_(new Ui_SettingsDialog),
|
||||||
loading_settings_(false) {
|
loading_settings_(false),
|
||||||
|
output_changed_(false) {
|
||||||
|
|
||||||
ui_->setupUi(this);
|
ui_->setupUi(this);
|
||||||
ui_->list->setItemDelegate(new SettingsItemDelegate(this));
|
ui_->list->setItemDelegate(new SettingsItemDelegate(this));
|
||||||
@ -203,6 +205,11 @@ void SettingsDialog::Save() {
|
|||||||
|
|
||||||
void SettingsDialog::accept() {
|
void SettingsDialog::accept() {
|
||||||
Save();
|
Save();
|
||||||
|
// Only Xine needs to reinitialize to switch output and device.
|
||||||
|
if (output_changed_ && engine() && engine()->type() == Engine::Xine && engine()->state() == Engine::Empty) {
|
||||||
|
engine()->ReloadSettings();
|
||||||
|
engine()->Init();
|
||||||
|
}
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QTreeWidgetItem>
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
|
#include "core/logging.h"
|
||||||
#include "widgets/osd.h"
|
#include "widgets/osd.h"
|
||||||
|
|
||||||
class QModelIndex;
|
class QModelIndex;
|
||||||
@ -104,6 +105,8 @@ public:
|
|||||||
// QWidget
|
// QWidget
|
||||||
void showEvent(QShowEvent *e);
|
void showEvent(QShowEvent *e);
|
||||||
|
|
||||||
|
void set_output_changed(bool output_changed) { output_changed_ = output_changed; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void NotificationPreview(OSD::Behaviour, QString, QString);
|
void NotificationPreview(OSD::Behaviour, QString, QString);
|
||||||
|
|
||||||
@ -135,6 +138,8 @@ private:
|
|||||||
bool loading_settings_;
|
bool loading_settings_;
|
||||||
|
|
||||||
QMap<Page, PageData> pages_;
|
QMap<Page, PageData> pages_;
|
||||||
|
|
||||||
|
bool output_changed_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SETTINGSDIALOG_H
|
#endif // SETTINGSDIALOG_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user