@@ -400,7 +400,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
app_->player()->Init();
|
app_->player()->Init();
|
||||||
EngineChanged(app_->player()->engine()->type());
|
EngineChanged(app_->player()->engine()->type());
|
||||||
const uint volume = app_->player()->GetVolume();
|
const uint volume = app_->player()->GetVolume();
|
||||||
ui_->volume->SetValueFromVolume(volume);
|
ui_->volume->SetValue(volume);
|
||||||
VolumeChanged(volume);
|
VolumeChanged(volume);
|
||||||
|
|
||||||
// Models
|
// Models
|
||||||
@@ -583,7 +583,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
ui_->stop_button->setMenu(stop_menu);
|
ui_->stop_button->setMenu(stop_menu);
|
||||||
|
|
||||||
// Player connections
|
// Player connections
|
||||||
QObject::connect(ui_->volume, &VolumeSlider::valueChanged, app_->player(), &Player::SetVolumeFromValue);
|
QObject::connect(ui_->volume, &VolumeSlider::valueChanged, app_->player(), &Player::SetVolumeFromSlider);
|
||||||
|
|
||||||
QObject::connect(app_->player(), &Player::EngineChanged, this, &MainWindow::EngineChanged);
|
QObject::connect(app_->player(), &Player::EngineChanged, this, &MainWindow::EngineChanged);
|
||||||
QObject::connect(app_->player(), &Player::Error, this, &MainWindow::ShowErrorDialog);
|
QObject::connect(app_->player(), &Player::Error, this, &MainWindow::ShowErrorDialog);
|
||||||
@@ -606,7 +606,7 @@ MainWindow::MainWindow(Application *app, std::shared_ptr<SystemTrayIcon> tray_ic
|
|||||||
QObject::connect(app_->player(), &Player::Stopped, osd_, &OSDBase::Stopped);
|
QObject::connect(app_->player(), &Player::Stopped, osd_, &OSDBase::Stopped);
|
||||||
QObject::connect(app_->player(), &Player::PlaylistFinished, osd_, &OSDBase::PlaylistFinished);
|
QObject::connect(app_->player(), &Player::PlaylistFinished, osd_, &OSDBase::PlaylistFinished);
|
||||||
QObject::connect(app_->player(), &Player::VolumeChanged, osd_, &OSDBase::VolumeChanged);
|
QObject::connect(app_->player(), &Player::VolumeChanged, osd_, &OSDBase::VolumeChanged);
|
||||||
QObject::connect(app_->player(), &Player::VolumeChanged, ui_->volume, &VolumeSlider::SetValueFromVolume);
|
QObject::connect(app_->player(), &Player::VolumeChanged, ui_->volume, &VolumeSlider::SetValue);
|
||||||
QObject::connect(app_->player(), &Player::ForceShowOSD, this, &MainWindow::ForceShowOSD);
|
QObject::connect(app_->player(), &Player::ForceShowOSD, this, &MainWindow::ForceShowOSD);
|
||||||
|
|
||||||
QObject::connect(app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, this, &MainWindow::SongChanged);
|
QObject::connect(app_->playlist_manager(), &PlaylistManager::CurrentSongChanged, this, &MainWindow::SongChanged);
|
||||||
@@ -1201,6 +1201,7 @@ void MainWindow::SaveSettings() {
|
|||||||
|
|
||||||
SaveGeometry();
|
SaveGeometry();
|
||||||
SavePlaybackStatus();
|
SavePlaybackStatus();
|
||||||
|
app_->player()->SaveVolume();
|
||||||
ui_->tabs->SaveSettings(kSettingsGroup);
|
ui_->tabs->SaveSettings(kSettingsGroup);
|
||||||
ui_->playlist->view()->SaveSettings();
|
ui_->playlist->view()->SaveSettings();
|
||||||
app_->scrobbler()->WriteCache();
|
app_->scrobbler()->WriteCache();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -175,7 +176,9 @@ void Mpris2::EngineStateChanged(Engine::State newState) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mpris2::VolumeChanged() { EmitNotification("Volume"); }
|
void Mpris2::VolumeChanged() {
|
||||||
|
EmitNotification("Volume");
|
||||||
|
}
|
||||||
|
|
||||||
void Mpris2::ShuffleModeChanged() { EmitNotification("Shuffle"); }
|
void Mpris2::ShuffleModeChanged() { EmitNotification("Shuffle"); }
|
||||||
|
|
||||||
@@ -411,8 +414,8 @@ double Mpris2::Volume() const {
|
|||||||
return app_->player()->GetVolume() / 100.0;
|
return app_->player()->GetVolume() / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mpris2::SetVolume(const double value) {
|
void Mpris2::SetVolume(const double volume) {
|
||||||
app_->player()->SetVolume(static_cast<uint>(std::max(std::min(lround(value * 100.0), 100L), 0L)));
|
app_->player()->SetVolume(static_cast<uint>(qBound(0L, lround(volume * 100.0), 100L)));
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 Mpris2::Position() const {
|
qint64 Mpris2::Position() const {
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ class Mpris2 : public QObject {
|
|||||||
void SetShuffle(bool enable);
|
void SetShuffle(bool enable);
|
||||||
QVariantMap Metadata() const;
|
QVariantMap Metadata() const;
|
||||||
double Volume() const;
|
double Volume() const;
|
||||||
void SetVolume(const double value);
|
void SetVolume(const double volume);
|
||||||
qint64 Position() const;
|
qint64 Position() const;
|
||||||
double MaximumRate() const;
|
double MaximumRate() const;
|
||||||
double MinimumRate() const;
|
double MinimumRate() const;
|
||||||
|
|||||||
@@ -83,29 +83,24 @@ Player::Player(Application *app, QObject *parent)
|
|||||||
autoscroll_(Playlist::AutoScroll_Maybe),
|
autoscroll_(Playlist::AutoScroll_Maybe),
|
||||||
last_state_(Engine::Empty),
|
last_state_(Engine::Empty),
|
||||||
nb_errors_received_(0),
|
nb_errors_received_(0),
|
||||||
|
volume_(100),
|
||||||
volume_before_mute_(100),
|
volume_before_mute_(100),
|
||||||
last_pressed_previous_(QDateTime::currentDateTime()),
|
last_pressed_previous_(QDateTime::currentDateTime()),
|
||||||
continue_on_error_(false),
|
continue_on_error_(false),
|
||||||
greyout_(true),
|
greyout_(true),
|
||||||
menu_previousmode_(BehaviourSettingsPage::PreviousBehaviour_DontRestart),
|
menu_previousmode_(BehaviourSettingsPage::PreviousBehaviour_DontRestart),
|
||||||
seek_step_sec_(10),
|
seek_step_sec_(10),
|
||||||
volume_control_(true),
|
|
||||||
play_offset_nanosec_(0) {
|
play_offset_nanosec_(0) {
|
||||||
|
|
||||||
settings_.beginGroup(kSettingsGroup);
|
|
||||||
|
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
||||||
Engine::EngineType enginetype = Engine::EngineTypeFromName(s.value("engine", EngineName(Engine::GStreamer)).toString().toLower());
|
Engine::EngineType enginetype = Engine::EngineTypeFromName(s.value("engine", EngineName(Engine::GStreamer)).toString().toLower());
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
CreateEngine(enginetype);
|
CreateEngine(enginetype);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::~Player() {
|
|
||||||
settings_.endGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
Engine::EngineType Player::CreateEngine(Engine::EngineType enginetype) {
|
Engine::EngineType Player::CreateEngine(Engine::EngineType enginetype) {
|
||||||
|
|
||||||
Engine::EngineType use_enginetype(Engine::None);
|
Engine::EngineType use_enginetype(Engine::None);
|
||||||
@@ -181,6 +176,7 @@ void Player::Init() {
|
|||||||
QObject::connect(engine_.get(), &EngineBase::TrackAboutToEnd, this, &Player::TrackAboutToEnd);
|
QObject::connect(engine_.get(), &EngineBase::TrackAboutToEnd, this, &Player::TrackAboutToEnd);
|
||||||
QObject::connect(engine_.get(), &EngineBase::TrackEnded, this, &Player::TrackEnded);
|
QObject::connect(engine_.get(), &EngineBase::TrackEnded, this, &Player::TrackEnded);
|
||||||
QObject::connect(engine_.get(), &EngineBase::MetaData, this, &Player::EngineMetadataReceived);
|
QObject::connect(engine_.get(), &EngineBase::MetaData, this, &Player::EngineMetadataReceived);
|
||||||
|
QObject::connect(engine_.get(), &EngineBase::VolumeChanged, this, &Player::SetVolumeFromEngine);
|
||||||
|
|
||||||
// Equalizer
|
// Equalizer
|
||||||
QObject::connect(equalizer_, &Equalizer::StereoBalancerEnabledChanged, app_->player()->engine(), &EngineBase::SetStereoBalancerEnabled);
|
QObject::connect(equalizer_, &Equalizer::StereoBalancerEnabledChanged, app_->player()->engine(), &EngineBase::SetStereoBalancerEnabled);
|
||||||
@@ -193,17 +189,10 @@ void Player::Init() {
|
|||||||
engine_->SetEqualizerEnabled(equalizer_->is_equalizer_enabled());
|
engine_->SetEqualizerEnabled(equalizer_->is_equalizer_enabled());
|
||||||
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
engine_->SetEqualizerParameters(equalizer_->preamp_value(), equalizer_->gain_values());
|
||||||
|
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
|
||||||
volume_control_ = s.value("volume_control", true).toBool();
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
if (volume_control_) {
|
|
||||||
int volume = settings_.value("volume", 100).toInt();
|
|
||||||
SetVolume(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReloadSettings();
|
ReloadSettings();
|
||||||
|
|
||||||
|
LoadVolume();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::ReloadSettings() {
|
void Player::ReloadSettings() {
|
||||||
@@ -220,15 +209,30 @@ 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();
|
||||||
|
|
||||||
s.beginGroup(BackendSettingsPage::kSettingsGroup);
|
|
||||||
bool volume_control = s.value("volume_control", true).toBool();
|
|
||||||
if (!volume_control && GetVolume() != 100) SetVolume(100);
|
|
||||||
s.endGroup();
|
|
||||||
|
|
||||||
engine_->ReloadSettings();
|
engine_->ReloadSettings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::LoadVolume() {
|
||||||
|
|
||||||
|
QSettings s;
|
||||||
|
s.beginGroup(kSettingsGroup);
|
||||||
|
const uint volume = s.value("volume", 100).toInt();
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
SetVolume(volume);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::SaveVolume() {
|
||||||
|
|
||||||
|
QSettings s;
|
||||||
|
s.beginGroup(kSettingsGroup);
|
||||||
|
s.setValue("volume", volume_);
|
||||||
|
s.endGroup();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
|
||||||
|
|
||||||
if (loading_async_.contains(result.original_url_)) {
|
if (loading_async_.contains(result.original_url_)) {
|
||||||
@@ -641,23 +645,35 @@ uint Player::GetVolume() const {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::SetVolumeFromValue(const int value) {
|
void Player::SetVolumeFromSlider(const int value) {
|
||||||
|
|
||||||
SetVolume(static_cast<uint>(std::max(0, value)));
|
const uint volume = static_cast<uint>(qBound(0, value, 100));
|
||||||
|
if (volume != volume_) {
|
||||||
|
engine_->SetVolume(volume);
|
||||||
|
emit VolumeChanged(volume_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::SetVolumeFromEngine(const uint volume) {
|
||||||
|
|
||||||
|
const uint new_volume = qBound(0U, volume, 100U);
|
||||||
|
if (new_volume != volume_) {
|
||||||
|
volume_ = new_volume;
|
||||||
|
emit VolumeChanged(volume_);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::SetVolume(const uint volume) {
|
void Player::SetVolume(const uint volume) {
|
||||||
|
|
||||||
uint old_volume = engine_->volume();
|
const uint new_volume = qBound(0U, volume, 100U);
|
||||||
uint new_volume = qBound(0U, volume, 100U);
|
if (new_volume != volume_) {
|
||||||
settings_.setValue("volume", new_volume);
|
engine_->SetVolume(volume);
|
||||||
engine_->SetVolume(new_volume);
|
volume_ = new_volume;
|
||||||
|
emit VolumeChanged(volume_);
|
||||||
if (new_volume != old_volume) {
|
|
||||||
emit VolumeChanged(new_volume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::VolumeUp() {
|
void Player::VolumeUp() {
|
||||||
@@ -794,8 +810,6 @@ PlaylistItemPtr Player::GetItemAt(const int pos) const {
|
|||||||
|
|
||||||
void Player::Mute() {
|
void Player::Mute() {
|
||||||
|
|
||||||
if (!volume_control_) return;
|
|
||||||
|
|
||||||
const uint current_volume = engine_->volume();
|
const uint current_volume = engine_->volume();
|
||||||
|
|
||||||
if (current_volume == 0) {
|
if (current_volume == 0) {
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QSettings>
|
|
||||||
|
|
||||||
#include "urlhandler.h"
|
#include "urlhandler.h"
|
||||||
#include "engine/engine_fwd.h"
|
#include "engine/engine_fwd.h"
|
||||||
@@ -71,6 +70,8 @@ class PlayerInterface : public QObject {
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void ReloadSettings() = 0;
|
virtual void ReloadSettings() = 0;
|
||||||
|
virtual void LoadVolume() = 0;
|
||||||
|
virtual void SaveVolume() = 0;
|
||||||
|
|
||||||
// Manual track change to the specified track
|
// Manual track change to the specified track
|
||||||
virtual void PlayAt(const int index, const quint64 offset_nanosec, Engine::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) = 0;
|
virtual void PlayAt(const int index, const quint64 offset_nanosec, Engine::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) = 0;
|
||||||
@@ -84,7 +85,8 @@ class PlayerInterface : public QObject {
|
|||||||
virtual void Next() = 0;
|
virtual void Next() = 0;
|
||||||
virtual void Previous() = 0;
|
virtual void Previous() = 0;
|
||||||
virtual void PlayPlaylist(const QString &playlist_name) = 0;
|
virtual void PlayPlaylist(const QString &playlist_name) = 0;
|
||||||
virtual void SetVolumeFromValue(const int value) = 0;
|
virtual void SetVolumeFromEngine(const uint volume) = 0;
|
||||||
|
virtual void SetVolumeFromSlider(const int value) = 0;
|
||||||
virtual void SetVolume(const uint volume) = 0;
|
virtual void SetVolume(const uint volume) = 0;
|
||||||
virtual void VolumeUp() = 0;
|
virtual void VolumeUp() = 0;
|
||||||
virtual void VolumeDown() = 0;
|
virtual void VolumeDown() = 0;
|
||||||
@@ -133,7 +135,6 @@ class Player : public PlayerInterface {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Player(Application *app, QObject *parent);
|
explicit Player(Application *app, QObject *parent);
|
||||||
~Player() override;
|
|
||||||
|
|
||||||
static const char *kSettingsGroup;
|
static const char *kSettingsGroup;
|
||||||
|
|
||||||
@@ -159,6 +160,8 @@ class Player : public PlayerInterface {
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void ReloadSettings() override;
|
void ReloadSettings() override;
|
||||||
|
void LoadVolume() override;
|
||||||
|
void SaveVolume() override;
|
||||||
|
|
||||||
void PlayAt(const int index, const quint64 offset_nanosec, Engine::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) override;
|
void PlayAt(const int index, const quint64 offset_nanosec, Engine::TrackChangeFlags change, const Playlist::AutoScroll autoscroll, const bool reshuffle, const bool force_inform = false) override;
|
||||||
void PlayPause(const quint64 offset_nanosec = 0, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll_Always) override;
|
void PlayPause(const quint64 offset_nanosec = 0, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll_Always) override;
|
||||||
@@ -167,8 +170,9 @@ class Player : public PlayerInterface {
|
|||||||
void Next() override;
|
void Next() override;
|
||||||
void Previous() override;
|
void Previous() override;
|
||||||
void PlayPlaylist(const QString &playlist_name) override;
|
void PlayPlaylist(const QString &playlist_name) override;
|
||||||
void SetVolumeFromValue(const int value) override;
|
void SetVolumeFromSlider(const int value) override;
|
||||||
void SetVolume(const uint value) override;
|
void SetVolumeFromEngine(const uint volume) override;
|
||||||
|
void SetVolume(const uint volume) override;
|
||||||
void VolumeUp() override;
|
void VolumeUp() override;
|
||||||
void VolumeDown() override;
|
void VolumeDown() override;
|
||||||
void SeekTo(const quint64 seconds) override;
|
void SeekTo(const quint64 seconds) override;
|
||||||
@@ -225,8 +229,6 @@ class Player : public PlayerInterface {
|
|||||||
AnalyzerContainer *analyzer_;
|
AnalyzerContainer *analyzer_;
|
||||||
Equalizer *equalizer_;
|
Equalizer *equalizer_;
|
||||||
|
|
||||||
QSettings settings_;
|
|
||||||
|
|
||||||
PlaylistItemPtr current_item_;
|
PlaylistItemPtr current_item_;
|
||||||
|
|
||||||
Engine::TrackChangeFlags stream_change_type_;
|
Engine::TrackChangeFlags stream_change_type_;
|
||||||
@@ -237,6 +239,7 @@ class Player : public PlayerInterface {
|
|||||||
QMap<QString, UrlHandler*> url_handlers_;
|
QMap<QString, UrlHandler*> url_handlers_;
|
||||||
|
|
||||||
QList<QUrl> loading_async_;
|
QList<QUrl> loading_async_;
|
||||||
|
uint volume_;
|
||||||
uint volume_before_mute_;
|
uint volume_before_mute_;
|
||||||
QDateTime last_pressed_previous_;
|
QDateTime last_pressed_previous_;
|
||||||
|
|
||||||
@@ -245,8 +248,6 @@ class Player : public PlayerInterface {
|
|||||||
BehaviourSettingsPage::PreviousBehaviour menu_previousmode_;
|
BehaviourSettingsPage::PreviousBehaviour menu_previousmode_;
|
||||||
int seek_step_sec_;
|
int seek_step_sec_;
|
||||||
|
|
||||||
bool volume_control_;
|
|
||||||
|
|
||||||
QDateTime pause_time_;
|
QDateTime pause_time_;
|
||||||
quint64 play_offset_nanosec_;
|
quint64 play_offset_nanosec_;
|
||||||
|
|
||||||
|
|||||||
@@ -99,16 +99,18 @@ bool Engine::Base::Play(const QUrl &stream_url, const QUrl &original_url, const
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Base::SetVolume(const uint value) {
|
void Engine::Base::UpdateVolume(const uint volume) {
|
||||||
|
|
||||||
volume_ = value;
|
volume_ = volume;
|
||||||
SetVolumeSW(MakeVolumeLogarithmic(value));
|
emit VolumeChanged(volume);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint Engine::Base::MakeVolumeLogarithmic(const uint volume) {
|
void Engine::Base::SetVolume(const uint volume) {
|
||||||
// We're using a logarithmic function to make the volume ramp more natural.
|
|
||||||
return static_cast<uint>(100 - 100.0 * std::log10((100 - volume) * 0.09 + 1.0));
|
volume_ = volume;
|
||||||
|
SetVolumeSW(volume);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Base::ReloadSettings() {
|
void Engine::Base::ReloadSettings() {
|
||||||
|
|||||||
@@ -97,11 +97,11 @@ class Base : public QObject {
|
|||||||
// 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.
|
||||||
bool Play(const QUrl &stream_url, const QUrl &original_url, const TrackChangeFlags flags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec, const quint64 offset_nanosec);
|
bool Play(const QUrl &stream_url, const QUrl &original_url, const TrackChangeFlags flags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec, const quint64 offset_nanosec);
|
||||||
void SetVolume(const uint value);
|
void SetVolume(const uint volume);
|
||||||
static uint MakeVolumeLogarithmic(const uint volume);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void ReloadSettings();
|
virtual void ReloadSettings();
|
||||||
|
void UpdateVolume(const uint volume);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void EmitAboutToEnd();
|
void EmitAboutToEnd();
|
||||||
@@ -153,6 +153,8 @@ class Base : public QObject {
|
|||||||
// Always use the state from event, because it's not guaranteed that immediate subsequent call to state() won't return a stale value.
|
// Always use the state from event, because it's not guaranteed that immediate subsequent call to state() won't return a stale value.
|
||||||
void StateChanged(Engine::State);
|
void StateChanged(Engine::State);
|
||||||
|
|
||||||
|
void VolumeChanged(uint volume);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
struct PluginDetails {
|
struct PluginDetails {
|
||||||
|
|||||||
@@ -340,8 +340,8 @@ void GstEngine::Seek(const quint64 offset_nanosec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEngine::SetVolumeSW(const uint percent) {
|
void GstEngine::SetVolumeSW(const uint volume) {
|
||||||
if (current_pipeline_) current_pipeline_->SetVolume(percent);
|
if (current_pipeline_) current_pipeline_->SetVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 GstEngine::position_nanosec() const {
|
qint64 GstEngine::position_nanosec() const {
|
||||||
@@ -802,6 +802,7 @@ std::shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline() {
|
|||||||
ret->set_proxy_settings(proxy_address_, proxy_authentication_, proxy_user_, proxy_pass_);
|
ret->set_proxy_settings(proxy_address_, proxy_authentication_, proxy_user_, proxy_pass_);
|
||||||
ret->set_channels(channels_enabled_, channels_);
|
ret->set_channels(channels_enabled_, channels_);
|
||||||
ret->set_bs2b_enabled(bs2b_enabled_);
|
ret->set_bs2b_enabled(bs2b_enabled_);
|
||||||
|
ret->set_fading_enabled(fadeout_enabled_ || autocrossfade_enabled_ || fadeout_pause_enabled_);
|
||||||
|
|
||||||
ret->AddBufferConsumer(this);
|
ret->AddBufferConsumer(this);
|
||||||
for (GstBufferConsumer *consumer : buffer_consumers_) {
|
for (GstBufferConsumer *consumer : buffer_consumers_) {
|
||||||
@@ -814,6 +815,7 @@ std::shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline() {
|
|||||||
QObject::connect(ret.get(), &GstEnginePipeline::BufferingStarted, this, &GstEngine::BufferingStarted);
|
QObject::connect(ret.get(), &GstEnginePipeline::BufferingStarted, this, &GstEngine::BufferingStarted);
|
||||||
QObject::connect(ret.get(), &GstEnginePipeline::BufferingProgress, this, &GstEngine::BufferingProgress);
|
QObject::connect(ret.get(), &GstEnginePipeline::BufferingProgress, this, &GstEngine::BufferingProgress);
|
||||||
QObject::connect(ret.get(), &GstEnginePipeline::BufferingFinished, this, &GstEngine::BufferingFinished);
|
QObject::connect(ret.get(), &GstEnginePipeline::BufferingFinished, this, &GstEngine::BufferingFinished);
|
||||||
|
QObject::connect(ret.get(), &GstEnginePipeline::VolumeChanged, this, &EngineBase::UpdateVolume);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
|
|||||||
void Seek(const quint64 offset_nanosec) override;
|
void Seek(const quint64 offset_nanosec) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetVolumeSW(const uint percent) override;
|
void SetVolumeSW(const uint volume) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
qint64 position_nanosec() const override;
|
qint64 position_nanosec() const override;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cmath>
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
@@ -70,6 +71,7 @@ GstEnginePipeline::GstEnginePipeline(QObject *parent)
|
|||||||
stereo_balancer_enabled_(false),
|
stereo_balancer_enabled_(false),
|
||||||
eq_enabled_(false),
|
eq_enabled_(false),
|
||||||
rg_enabled_(false),
|
rg_enabled_(false),
|
||||||
|
fading_enabled_(false),
|
||||||
stereo_balance_(0.0F),
|
stereo_balance_(0.0F),
|
||||||
eq_preamp_(0),
|
eq_preamp_(0),
|
||||||
rg_mode_(0),
|
rg_mode_(0),
|
||||||
@@ -97,18 +99,19 @@ GstEnginePipeline::GstEnginePipeline(QObject *parent)
|
|||||||
last_known_position_ns_(0),
|
last_known_position_ns_(0),
|
||||||
next_uri_set_(false),
|
next_uri_set_(false),
|
||||||
volume_percent_(100),
|
volume_percent_(100),
|
||||||
volume_modifier_(1.0F),
|
|
||||||
use_fudge_timer_(false),
|
use_fudge_timer_(false),
|
||||||
pipeline_(nullptr),
|
pipeline_(nullptr),
|
||||||
audiobin_(nullptr),
|
audiobin_(nullptr),
|
||||||
audioqueue_(nullptr),
|
audioqueue_(nullptr),
|
||||||
volume_(nullptr),
|
volume_(nullptr),
|
||||||
|
volume_fading_(nullptr),
|
||||||
audiopanorama_(nullptr),
|
audiopanorama_(nullptr),
|
||||||
equalizer_(nullptr),
|
equalizer_(nullptr),
|
||||||
equalizer_preamp_(nullptr),
|
equalizer_preamp_(nullptr),
|
||||||
pad_added_cb_id_(-1),
|
pad_added_cb_id_(-1),
|
||||||
notify_source_cb_id_(-1),
|
notify_source_cb_id_(-1),
|
||||||
about_to_finish_cb_id_(-1),
|
about_to_finish_cb_id_(-1),
|
||||||
|
notify_volume_cb_id_(-1),
|
||||||
logged_unsupported_analyzer_format_(false) {
|
logged_unsupported_analyzer_format_(false) {
|
||||||
|
|
||||||
eq_band_gains_.reserve(kEqBandCount);
|
eq_band_gains_.reserve(kEqBandCount);
|
||||||
@@ -139,6 +142,10 @@ GstEnginePipeline::~GstEnginePipeline() {
|
|||||||
g_signal_handler_disconnect(G_OBJECT(pipeline_), about_to_finish_cb_id_);
|
g_signal_handler_disconnect(G_OBJECT(pipeline_), about_to_finish_cb_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (notify_volume_cb_id_ != -1) {
|
||||||
|
g_signal_handler_disconnect(G_OBJECT(volume_), notify_volume_cb_id_);
|
||||||
|
}
|
||||||
|
|
||||||
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
|
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
|
||||||
if (bus) {
|
if (bus) {
|
||||||
gst_bus_remove_watch(bus);
|
gst_bus_remove_watch(bus);
|
||||||
@@ -218,6 +225,10 @@ void GstEnginePipeline::set_bs2b_enabled(const bool enabled) {
|
|||||||
bs2b_enabled_ = enabled;
|
bs2b_enabled_ = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GstEnginePipeline::set_fading_enabled(const bool enabled) {
|
||||||
|
fading_enabled_ = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
GstElement *GstEnginePipeline::CreateElement(const QString &factory_name, const QString &name, GstElement *bin, QString &error) const {
|
GstElement *GstEnginePipeline::CreateElement(const QString &factory_name, const QString &name, GstElement *bin, QString &error) const {
|
||||||
|
|
||||||
QString unique_name = QString("pipeline") + "-" + QString::number(id_) + "-" + (name.isEmpty() ? factory_name : name);
|
QString unique_name = QString("pipeline") + "-" + QString::number(id_) + "-" + (name.isEmpty() ? factory_name : name);
|
||||||
@@ -249,6 +260,10 @@ bool GstEnginePipeline::InitFromUrl(const QByteArray &stream_url, const QUrl &or
|
|||||||
|
|
||||||
if (!InitAudioBin(error)) return false;
|
if (!InitAudioBin(error)) return false;
|
||||||
|
|
||||||
|
if (volume_) {
|
||||||
|
notify_volume_cb_id_ = CHECKED_GCONNECT(G_OBJECT(volume_), "notify::volume", &VolumeCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
// Set playbin's sink to be our custom audio-sink.
|
// Set playbin's sink to be our custom audio-sink.
|
||||||
g_object_set(GST_OBJECT(pipeline_), "audio-sink", audiobin_, nullptr);
|
g_object_set(GST_OBJECT(pipeline_), "audio-sink", audiobin_, nullptr);
|
||||||
|
|
||||||
@@ -256,14 +271,9 @@ bool GstEnginePipeline::InitFromUrl(const QByteArray &stream_url, const QUrl &or
|
|||||||
g_object_get(G_OBJECT(pipeline_), "flags", &flags, nullptr);
|
g_object_get(G_OBJECT(pipeline_), "flags", &flags, nullptr);
|
||||||
flags |= 0x00000002;
|
flags |= 0x00000002;
|
||||||
flags &= ~0x00000001;
|
flags &= ~0x00000001;
|
||||||
if (volume_enabled_) {
|
flags &= ~0x00000010;
|
||||||
flags |= 0x00000010;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
flags &= ~0x00000010;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_set(G_OBJECT(pipeline_), "flags", flags, nullptr);
|
g_object_set(G_OBJECT(pipeline_), "flags", flags, nullptr);
|
||||||
|
|
||||||
g_object_set(G_OBJECT(pipeline_), "uri", stream_url.constData(), nullptr);
|
g_object_set(G_OBJECT(pipeline_), "uri", stream_url.constData(), nullptr);
|
||||||
|
|
||||||
pipeline_is_connected_ = true;
|
pipeline_is_connected_ = true;
|
||||||
@@ -394,6 +404,11 @@ bool GstEnginePipeline::InitAudioBin(QString &error) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_object_class_find_property(G_OBJECT_GET_CLASS(audiosink), "volume")) {
|
||||||
|
qLog(Debug) << output_ << "has volume element, enabling system volume synchronization.";
|
||||||
|
volume_ = audiosink;
|
||||||
|
}
|
||||||
|
|
||||||
// Create all the other elements
|
// Create all the other elements
|
||||||
|
|
||||||
audioqueue_ = CreateElement("queue2", "audioqueue", audiobin_, error);
|
audioqueue_ = CreateElement("queue2", "audioqueue", audiobin_, error);
|
||||||
@@ -411,9 +426,20 @@ bool GstEnginePipeline::InitAudioBin(QString &error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the volume elements if it's enabled.
|
// Create the volume elements if it's enabled.
|
||||||
if (volume_enabled_) {
|
GstElement *swvolume = nullptr;
|
||||||
volume_ = CreateElement("volume", "volume", audiobin_, error);
|
if (volume_enabled_ && !volume_) {
|
||||||
if (!volume_) {
|
swvolume = CreateElement("volume", "volume_sw", audiobin_, error);
|
||||||
|
if (!swvolume) {
|
||||||
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
|
audiobin_ = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
volume_ = swvolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fading_enabled_) {
|
||||||
|
volume_fading_ = CreateElement("volume", "volume_fading", audiobin_, error);
|
||||||
|
if (!volume_fading_) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
return false;
|
return false;
|
||||||
@@ -561,69 +587,80 @@ bool GstEnginePipeline::InitAudioBin(QString &error) {
|
|||||||
|
|
||||||
// Link all elements
|
// Link all elements
|
||||||
|
|
||||||
GstElement *next = audioqueue_; // The next element to link from.
|
if (!gst_element_link(audioqueue_, audioconverter)) {
|
||||||
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
|
audiobin_ = nullptr;
|
||||||
|
error = "gst_element_link() failed.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstElement *element_link = audioconverter; // The next element to link from.
|
||||||
|
|
||||||
// Link replaygain elements if enabled.
|
// Link replaygain elements if enabled.
|
||||||
if (rg_enabled_ && rgvolume && rglimiter && rgconverter) {
|
if (rg_enabled_ && rgvolume && rglimiter && rgconverter) {
|
||||||
if (!gst_element_link_many(next, rgvolume, rglimiter, rgconverter, nullptr)) {
|
if (!gst_element_link_many(element_link, rgvolume, rglimiter, rgconverter, nullptr)) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
error = "gst_element_link_many() failed.";
|
error = "gst_element_link_many() failed.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next = rgconverter;
|
element_link = rgconverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link equalizer elements if enabled.
|
// Link equalizer elements if enabled.
|
||||||
if (eq_enabled_ && equalizer_ && equalizer_preamp_) {
|
if (eq_enabled_ && equalizer_ && equalizer_preamp_) {
|
||||||
if (!gst_element_link_many(next, equalizer_preamp_, equalizer_, nullptr)) {
|
if (!gst_element_link_many(element_link, equalizer_preamp_, equalizer_, nullptr)) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
error = "gst_element_link_many() failed.";
|
error = "gst_element_link_many() failed.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next = equalizer_;
|
element_link = equalizer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link stereo balancer elements if enabled.
|
// Link stereo balancer elements if enabled.
|
||||||
if (stereo_balancer_enabled_ && audiopanorama_) {
|
if (stereo_balancer_enabled_ && audiopanorama_) {
|
||||||
if (!gst_element_link(next, audiopanorama_)) {
|
if (!gst_element_link(element_link, audiopanorama_)) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
error = "gst_element_link() failed.";
|
error = "gst_element_link() failed.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next = audiopanorama_;
|
element_link = audiopanorama_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link volume elements if enabled.
|
// Link software volume element if enabled.
|
||||||
if (volume_enabled_ && volume_) {
|
if (volume_enabled_ && swvolume) {
|
||||||
if (!gst_element_link(next, volume_)) {
|
if (!gst_element_link(element_link, swvolume)) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
error = "gst_element_link() failed.";
|
error = "gst_element_link() failed.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next = volume_;
|
element_link = swvolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link fading volume element if enabled.
|
||||||
|
if (fading_enabled_ && volume_fading_) {
|
||||||
|
if (!gst_element_link(element_link, volume_fading_)) {
|
||||||
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
|
audiobin_ = nullptr;
|
||||||
|
error = "gst_element_link() failed.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
element_link = volume_fading_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link bs2b element if enabled.
|
// Link bs2b element if enabled.
|
||||||
if (bs2b_enabled_ && bs2b) {
|
if (bs2b_enabled_ && bs2b) {
|
||||||
qLog(Debug) << "Enabling bs2b";
|
qLog(Debug) << "Enabling bs2b";
|
||||||
if (!gst_element_link(next, bs2b)) {
|
if (!gst_element_link(element_link, bs2b)) {
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
gst_object_unref(GST_OBJECT(audiobin_));
|
||||||
audiobin_ = nullptr;
|
audiobin_ = nullptr;
|
||||||
error = "gst_element_link() failed.";
|
error = "gst_element_link() failed.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
next = bs2b;
|
element_link = bs2b;
|
||||||
}
|
|
||||||
|
|
||||||
if (!gst_element_link(next, audioconverter)) {
|
|
||||||
gst_object_unref(GST_OBJECT(audiobin_));
|
|
||||||
audiobin_ = nullptr;
|
|
||||||
error = "gst_element_link() failed.";
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -638,12 +675,12 @@ bool GstEnginePipeline::InitAudioBin(QString &error) {
|
|||||||
qLog(Debug) << "Setting channels to" << channels_;
|
qLog(Debug) << "Setting channels to" << channels_;
|
||||||
gst_caps_set_simple(caps, "channels", G_TYPE_INT, channels_, nullptr);
|
gst_caps_set_simple(caps, "channels", G_TYPE_INT, channels_, nullptr);
|
||||||
}
|
}
|
||||||
gst_element_link_filtered(audioconverter, audiosink, caps);
|
gst_element_link_filtered(element_link, audiosink, caps);
|
||||||
gst_caps_unref(caps);
|
gst_caps_unref(caps);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Add probes and handlers.
|
{ // Add probes and handlers.
|
||||||
GstPad *pad = gst_element_get_static_pad(audioqueue_, "src");
|
GstPad *pad = gst_element_get_static_pad(audioconverter, "src");
|
||||||
if (pad) {
|
if (pad) {
|
||||||
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
|
gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER, HandoffCallback, this, nullptr);
|
||||||
gst_object_unref(pad);
|
gst_object_unref(pad);
|
||||||
@@ -738,6 +775,21 @@ void GstEnginePipeline::SourceSetupCallback(GstPlayBin *bin, GParamSpec*, gpoint
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GstEnginePipeline::VolumeCallback(GstElement*, GParamSpec*, gpointer self) {
|
||||||
|
|
||||||
|
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
|
||||||
|
|
||||||
|
gdouble volume = 0;
|
||||||
|
g_object_get(G_OBJECT(instance->volume_), "volume", &volume, nullptr);
|
||||||
|
|
||||||
|
const uint volume_percent = static_cast<uint>(qBound(0L, lround(qBound(0.0, gst_stream_volume_convert_volume(GST_STREAM_VOLUME_FORMAT_LINEAR, GST_STREAM_VOLUME_FORMAT_CUBIC, volume), 1.0) / 0.01), 100L));
|
||||||
|
if (volume_percent != instance->volume_percent_) {
|
||||||
|
instance->volume_percent_ = volume_percent;
|
||||||
|
emit instance->VolumeChanged(volume_percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::NewPadCallback(GstElement*, GstPad *pad, gpointer self) {
|
void GstEnginePipeline::NewPadCallback(GstElement*, GstPad *pad, gpointer self) {
|
||||||
|
|
||||||
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
|
GstEnginePipeline *instance = reinterpret_cast<GstEnginePipeline*>(self);
|
||||||
@@ -1355,27 +1407,22 @@ bool GstEnginePipeline::Seek(const qint64 nanosec) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::SetVolume(const uint percent) {
|
void GstEnginePipeline::SetVolume(const uint volume_percent) {
|
||||||
|
|
||||||
if (!volume_) return;
|
if (volume_) {
|
||||||
volume_percent_ = percent;
|
const double volume = gst_stream_volume_convert_volume(GST_STREAM_VOLUME_FORMAT_CUBIC, GST_STREAM_VOLUME_FORMAT_LINEAR, static_cast<double>(volume_percent) * 0.01);
|
||||||
UpdateVolume();
|
g_object_set(G_OBJECT(volume_), "volume", volume, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_percent_ = volume_percent;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GstEnginePipeline::SetVolumeModifier(const qreal mod) {
|
void GstEnginePipeline::SetFaderVolume(const qreal volume) {
|
||||||
|
|
||||||
if (!volume_) return;
|
if (volume_fading_) {
|
||||||
volume_modifier_ = mod;
|
g_object_set(G_OBJECT(volume_fading_), "volume", volume, nullptr);
|
||||||
UpdateVolume();
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void GstEnginePipeline::UpdateVolume() {
|
|
||||||
|
|
||||||
if (!volume_) return;
|
|
||||||
double vol = static_cast<double>(volume_percent_) * static_cast<double>(0.01) * volume_modifier_;
|
|
||||||
g_object_set(G_OBJECT(volume_), "volume", vol, nullptr);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1454,7 +1501,7 @@ void GstEnginePipeline::StartFader(const qint64 duration_nanosec, const QTimeLin
|
|||||||
}
|
}
|
||||||
timeline->deleteLater();
|
timeline->deleteLater();
|
||||||
});
|
});
|
||||||
QObject::connect(fader_.get(), &QTimeLine::valueChanged, this, &GstEnginePipeline::SetVolumeModifier);
|
QObject::connect(fader_.get(), &QTimeLine::valueChanged, this, &GstEnginePipeline::SetFaderVolume);
|
||||||
QObject::connect(fader_.get(), &QTimeLine::finished, this, &GstEnginePipeline::FaderTimelineFinished);
|
QObject::connect(fader_.get(), &QTimeLine::finished, this, &GstEnginePipeline::FaderTimelineFinished);
|
||||||
fader_->setDirection(direction);
|
fader_->setDirection(direction);
|
||||||
fader_->setEasingCurve(shape);
|
fader_->setEasingCurve(shape);
|
||||||
@@ -1464,7 +1511,7 @@ void GstEnginePipeline::StartFader(const qint64 duration_nanosec, const QTimeLin
|
|||||||
fader_fudge_timer_.stop();
|
fader_fudge_timer_.stop();
|
||||||
use_fudge_timer_ = use_fudge_timer;
|
use_fudge_timer_ = use_fudge_timer;
|
||||||
|
|
||||||
SetVolumeModifier(fader_->currentValue());
|
SetFaderVolume(fader_->currentValue());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
void set_proxy_settings(const QString &address, const bool authentication, const QString &user, const QString &pass);
|
void set_proxy_settings(const QString &address, const bool authentication, const QString &user, const QString &pass);
|
||||||
void set_channels(const bool enabled, const int channels);
|
void set_channels(const bool enabled, const int channels);
|
||||||
void set_bs2b_enabled(const bool enabled);
|
void set_bs2b_enabled(const bool enabled);
|
||||||
|
void set_fading_enabled(const bool enabled);
|
||||||
|
|
||||||
// Creates the pipeline, returns false on error
|
// Creates the pipeline, returns false on error
|
||||||
bool InitFromUrl(const QByteArray &stream_url, const QUrl &original_url, const qint64 end_nanosec, QString &error);
|
bool InitFromUrl(const QByteArray &stream_url, const QUrl &original_url, const qint64 end_nanosec, QString &error);
|
||||||
@@ -86,7 +87,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
// Control the music playback
|
// Control the music playback
|
||||||
QFuture<GstStateChangeReturn> SetState(const GstState state);
|
QFuture<GstStateChangeReturn> SetState(const GstState state);
|
||||||
Q_INVOKABLE bool Seek(const qint64 nanosec);
|
Q_INVOKABLE bool Seek(const qint64 nanosec);
|
||||||
void SetVolume(const uint percent);
|
void SetVolume(const uint volume_percent);
|
||||||
void SetStereoBalance(const float value);
|
void SetStereoBalance(const float value);
|
||||||
void SetEqualizerParams(const int preamp, const QList<int> &band_gains);
|
void SetEqualizerParams(const int preamp, const QList<int> &band_gains);
|
||||||
|
|
||||||
@@ -121,7 +122,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
QString source_device() const { return source_device_; }
|
QString source_device() const { return source_device_; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void SetVolumeModifier(qreal mod);
|
void SetFaderVolume(qreal mod);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void Error(int pipeline_id, int domain, int error_code, QString message, QString debug);
|
void Error(int pipeline_id, int domain, int error_code, QString message, QString debug);
|
||||||
@@ -129,6 +130,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
void EndOfStreamReached(int pipeline_id, bool has_next_track);
|
void EndOfStreamReached(int pipeline_id, bool has_next_track);
|
||||||
void MetadataFound(int pipeline_id, const Engine::SimpleMetaBundle &bundle);
|
void MetadataFound(int pipeline_id, const Engine::SimpleMetaBundle &bundle);
|
||||||
|
|
||||||
|
void VolumeChanged(uint volume);
|
||||||
void FaderFinished();
|
void FaderFinished();
|
||||||
|
|
||||||
void BufferingStarted();
|
void BufferingStarted();
|
||||||
@@ -145,6 +147,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
// Static callbacks. The GstEnginePipeline instance is passed in the last argument.
|
// Static callbacks. The GstEnginePipeline instance is passed in the last argument.
|
||||||
static GstPadProbeReturn EventHandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
|
static GstPadProbeReturn EventHandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
|
||||||
static void SourceSetupCallback(GstPlayBin*, GParamSpec *pspec, gpointer);
|
static void SourceSetupCallback(GstPlayBin*, GParamSpec *pspec, gpointer);
|
||||||
|
static void VolumeCallback(GstElement*, GParamSpec*, gpointer self);
|
||||||
static void NewPadCallback(GstElement*, GstPad*, gpointer);
|
static void NewPadCallback(GstElement*, GstPad*, gpointer);
|
||||||
static GstPadProbeReturn PlaybinProbe(GstPad*, GstPadProbeInfo*, gpointer);
|
static GstPadProbeReturn PlaybinProbe(GstPad*, GstPadProbeInfo*, gpointer);
|
||||||
static GstPadProbeReturn HandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
|
static GstPadProbeReturn HandoffCallback(GstPad*, GstPadProbeInfo*, gpointer);
|
||||||
@@ -164,7 +167,6 @@ class GstEnginePipeline : public QObject {
|
|||||||
static QString ParseStrTag(GstTagList *list, const char *tag);
|
static QString ParseStrTag(GstTagList *list, const char *tag);
|
||||||
static guint ParseUIntTag(GstTagList *list, const char *tag);
|
static guint ParseUIntTag(GstTagList *list, const char *tag);
|
||||||
|
|
||||||
void UpdateVolume();
|
|
||||||
void UpdateStereoBalance();
|
void UpdateStereoBalance();
|
||||||
void UpdateEqualizer();
|
void UpdateEqualizer();
|
||||||
|
|
||||||
@@ -190,6 +192,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
bool stereo_balancer_enabled_;
|
bool stereo_balancer_enabled_;
|
||||||
bool eq_enabled_;
|
bool eq_enabled_;
|
||||||
bool rg_enabled_;
|
bool rg_enabled_;
|
||||||
|
bool fading_enabled_;
|
||||||
|
|
||||||
// Stereo balance:
|
// Stereo balance:
|
||||||
// From -1.0 - 1.0
|
// From -1.0 - 1.0
|
||||||
@@ -271,7 +274,6 @@ class GstEnginePipeline : public QObject {
|
|||||||
bool next_uri_set_;
|
bool next_uri_set_;
|
||||||
|
|
||||||
uint volume_percent_;
|
uint volume_percent_;
|
||||||
qreal volume_modifier_;
|
|
||||||
|
|
||||||
std::shared_ptr<QTimeLine> fader_;
|
std::shared_ptr<QTimeLine> fader_;
|
||||||
QBasicTimer fader_fudge_timer_;
|
QBasicTimer fader_fudge_timer_;
|
||||||
@@ -281,6 +283,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
GstElement *audiobin_;
|
GstElement *audiobin_;
|
||||||
GstElement *audioqueue_;
|
GstElement *audioqueue_;
|
||||||
GstElement *volume_;
|
GstElement *volume_;
|
||||||
|
GstElement *volume_fading_;
|
||||||
GstElement *audiopanorama_;
|
GstElement *audiopanorama_;
|
||||||
GstElement *equalizer_;
|
GstElement *equalizer_;
|
||||||
GstElement *equalizer_preamp_;
|
GstElement *equalizer_preamp_;
|
||||||
@@ -288,6 +291,7 @@ class GstEnginePipeline : public QObject {
|
|||||||
int pad_added_cb_id_;
|
int pad_added_cb_id_;
|
||||||
int notify_source_cb_id_;
|
int notify_source_cb_id_;
|
||||||
int about_to_finish_cb_id_;
|
int about_to_finish_cb_id_;
|
||||||
|
int notify_volume_cb_id_;
|
||||||
|
|
||||||
QThreadPool set_state_threadpool_;
|
QThreadPool set_state_threadpool_;
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ BackendSettingsPage::BackendSettingsPage(SettingsDialog *dialog, QWidget *parent
|
|||||||
QObject::connect(ui_->checkbox_fadeout_stop, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
QObject::connect(ui_->checkbox_fadeout_stop, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
||||||
QObject::connect(ui_->checkbox_fadeout_cross, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
QObject::connect(ui_->checkbox_fadeout_cross, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
||||||
QObject::connect(ui_->checkbox_fadeout_auto, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
QObject::connect(ui_->checkbox_fadeout_auto, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
||||||
QObject::connect(ui_->checkbox_volume_control, &QCheckBox::toggled, this, &BackendSettingsPage::FadingOptionsChanged);
|
|
||||||
QObject::connect(ui_->checkbox_channels, &QCheckBox::toggled, ui_->widget_channels, &QSpinBox::setEnabled);
|
QObject::connect(ui_->checkbox_channels, &QCheckBox::toggled, ui_->widget_channels, &QSpinBox::setEnabled);
|
||||||
QObject::connect(ui_->button_buffer_defaults, &QPushButton::clicked, this, &BackendSettingsPage::BufferDefaults);
|
QObject::connect(ui_->button_buffer_defaults, &QPushButton::clicked, this, &BackendSettingsPage::BufferDefaults);
|
||||||
|
|
||||||
@@ -800,8 +799,7 @@ void BackendSettingsPage::FadingOptionsChanged() {
|
|||||||
|
|
||||||
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
EngineBase::OutputDetails output = ui_->combobox_output->itemData(ui_->combobox_output->currentIndex()).value<EngineBase::OutputDetails>();
|
||||||
if (engine()->type() == Engine::GStreamer &&
|
if (engine()->type() == Engine::GStreamer &&
|
||||||
!(engine()->ALSADeviceSupport(output.name) && !ui_->lineedit_device->text().isEmpty() && (ui_->lineedit_device->text().contains(QRegularExpression("^hw:.*")) || ui_->lineedit_device->text().contains(QRegularExpression("^plughw:.*")))) &&
|
!(engine()->ALSADeviceSupport(output.name) && !ui_->lineedit_device->text().isEmpty() && (ui_->lineedit_device->text().contains(QRegularExpression("^hw:.*")) || ui_->lineedit_device->text().contains(QRegularExpression("^plughw:.*"))))) {
|
||||||
ui_->checkbox_volume_control->isChecked()) {
|
|
||||||
ui_->groupbox_fading->setEnabled(true);
|
ui_->groupbox_fading->setEnabled(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ void SliderSlider::wheelEvent(QWheelEvent *e) {
|
|||||||
|
|
||||||
QSlider::setValue(nval);
|
QSlider::setValue(nval);
|
||||||
|
|
||||||
emit sliderReleased(value());
|
emit SliderReleased(value());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ void SliderSlider::mousePressEvent(QMouseEvent *e) {
|
|||||||
void SliderSlider::mouseReleaseEvent(QMouseEvent*) {
|
void SliderSlider::mouseReleaseEvent(QMouseEvent*) {
|
||||||
|
|
||||||
if (!outside_ && QSlider::value() != prev_value_) {
|
if (!outside_ && QSlider::value() != prev_value_) {
|
||||||
emit sliderReleased(value());
|
emit SliderReleased(value());
|
||||||
}
|
}
|
||||||
|
|
||||||
sliding_ = false;
|
sliding_ = false;
|
||||||
@@ -141,7 +141,7 @@ void SliderSlider::mouseReleaseEvent(QMouseEvent*) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SliderSlider::SetValueFromVolume(const uint value) {
|
void SliderSlider::SetValue(const uint value) {
|
||||||
|
|
||||||
setValue(static_cast<int>(value));
|
setValue(static_cast<int>(value));
|
||||||
|
|
||||||
@@ -298,21 +298,21 @@ void VolumeSlider::contextMenuEvent(QContextMenuEvent *e) {
|
|||||||
|
|
||||||
QAction *ret = menu.exec(mapToGlobal(e->pos()));
|
QAction *ret = menu.exec(mapToGlobal(e->pos()));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
QSlider::setValue(values[ret]); // clazy:exclude=skipped-base-method
|
QSlider::setValue(values[ret]);
|
||||||
emit sliderReleased(values[ret]);
|
emit SliderReleased(values[ret]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeSlider::slideEvent(QMouseEvent *e) {
|
void VolumeSlider::slideEvent(QMouseEvent *e) {
|
||||||
QSlider::setValue(QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x(), width() - 2)); // clazy:exclude=skipped-base-method
|
QSlider::setValue(QStyle::sliderValueFromPosition(minimum(), maximum(), e->pos().x(), width() - 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VolumeSlider::wheelEvent(QWheelEvent *e) {
|
void VolumeSlider::wheelEvent(QWheelEvent *e) {
|
||||||
|
|
||||||
const int step = e->angleDelta().y() / (e->angleDelta().x() == 0 ? 30 : -30);
|
const int step = e->angleDelta().y() / (e->angleDelta().x() == 0 ? 30 : -30);
|
||||||
QSlider::setValue(SliderSlider::value() + step); // clazy:exclude=skipped-base-method
|
QSlider::setValue(SliderSlider::value() + step);
|
||||||
emit sliderReleased(value());
|
emit SliderReleased(value());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ class SliderSlider : public QSlider {
|
|||||||
public:
|
public:
|
||||||
explicit SliderSlider(const Qt::Orientation, QWidget*, const int max = 0);
|
explicit SliderSlider(const Qt::Orientation, QWidget*, const int max = 0);
|
||||||
|
|
||||||
virtual void SetValueFromVolume(const uint value);
|
virtual void SetValue(const uint value);
|
||||||
virtual void setValue(int value);
|
virtual void setValue(int value);
|
||||||
|
|
||||||
// WARNING non-virtual - and thus only really intended for internal use this is a major flaw in the class presently, however it suits our current needs fine
|
// WARNING non-virtual - and thus only really intended for internal use this is a major flaw in the class presently, however it suits our current needs fine
|
||||||
int value() const { return adjustValue(QSlider::value()); }
|
int value() const { return adjustValue(QSlider::value()); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
// we emit this when the user has specifically changed the slider so connect to it if valueChanged() is too generic Qt also emits valueChanged(int)
|
// We emit this when the user has specifically changed the slider so connect to it if valueChanged() is too generic Qt also emits valueChanged(int)
|
||||||
void sliderReleased(int); // clazy:exclude=overloaded-signal
|
void SliderReleased(int);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void wheelEvent(QWheelEvent*) override;
|
void wheelEvent(QWheelEvent*) override;
|
||||||
|
|||||||
Reference in New Issue
Block a user