Rename EngineBase

This commit is contained in:
Jonas Kvinge
2023-04-22 19:13:42 +02:00
parent c3534affdb
commit e9f3281694
35 changed files with 451 additions and 500 deletions

View File

@@ -1,51 +0,0 @@
#ifndef ENGINE_FWD_H
#define ENGINE_FWD_H
#include <QtGlobal>
/// Used by eg engineobserver.h, and thus we reduce header dependencies on enginebase.h
namespace Engine {
struct SimpleMetaBundle;
class Base;
/**
* You should return:
* Playing when playing,
* Paused when paused
* Idle when you still have a URL loaded (ie you have not been told to stop())
* Empty when you have been told to stop(),
* Error when an error occurred and you stopped yourself
*
* It is vital to be Idle just after the track has ended!
*/
enum class State {
Empty,
Idle,
Playing,
Paused,
Error
};
enum TrackChangeType {
// One of:
First = 0x01,
Manual = 0x02,
Auto = 0x04,
Intro = 0x08,
// Any of:
SameAlbum = 0x10
};
Q_DECLARE_FLAGS(TrackChangeFlags, TrackChangeType)
} // namespace Engine
using EngineBase = Engine::Base;
Q_DECLARE_METATYPE(Engine::State)
Q_DECLARE_METATYPE(Engine::TrackChangeType)
#endif // ENGINE_FWD_H

View File

@@ -33,14 +33,12 @@
#include "utilities/envutils.h"
#include "utilities/timeconstants.h"
#include "core/networkproxyfactory.h"
#include "engine_fwd.h"
#include "enginebase.h"
#include "settings/backendsettingspage.h"
#include "settings/networkproxysettingspage.h"
Engine::Base::Base(const EngineType type, QObject *parent)
EngineBase::EngineBase(QObject *parent)
: QObject(parent),
type_(type),
volume_control_(true),
volume_(100),
beginning_nanosec_(0),
@@ -73,9 +71,40 @@ Engine::Base::Base(const EngineType type, QObject *parent)
strict_ssl_enabled_(false),
about_to_end_emitted_(false) {}
Engine::Base::~Base() = default;
EngineBase::~EngineBase() = default;
bool Engine::Base::Load(const QUrl &media_url, const QUrl &stream_url, const TrackChangeFlags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) {
EngineBase::Type EngineBase::TypeFromName(const QString &name) {
if (name.compare("gstreamer", Qt::CaseInsensitive) == 0) return Type::GStreamer;
if (name.compare("vlc", Qt::CaseInsensitive) == 0) return Type::VLC;
return Type::None;
}
QString EngineBase::Name(const Type type) {
switch (type) {
case Type::GStreamer: return QString("gstreamer");
case Type::VLC: return QString("vlc");
case Type::None:
default: return QString("None");
}
}
QString EngineBase::Description(const Type type) {
switch (type) {
case Type::GStreamer: return QString("GStreamer");
case Type::VLC: return QString("VLC");
case Type::None:
default: return QString("None");
}
}
bool EngineBase::Load(const QUrl &media_url, const QUrl &stream_url, const TrackChangeFlags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) {
Q_UNUSED(force_stop_at_end);
@@ -90,7 +119,7 @@ bool Engine::Base::Load(const QUrl &media_url, const QUrl &stream_url, const Tra
}
bool Engine::Base::Play(const QUrl &media_url, const QUrl &stream_url, const TrackChangeFlags flags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec, const quint64 offset_nanosec) {
bool EngineBase::Play(const QUrl &media_url, const QUrl &stream_url, const TrackChangeFlags flags, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec, const quint64 offset_nanosec) {
if (!Load(media_url, stream_url, flags, force_stop_at_end, beginning_nanosec, end_nanosec)) {
return false;
@@ -100,21 +129,21 @@ bool Engine::Base::Play(const QUrl &media_url, const QUrl &stream_url, const Tra
}
void Engine::Base::UpdateVolume(const uint volume) {
void EngineBase::UpdateVolume(const uint volume) {
volume_ = volume;
emit VolumeChanged(volume);
}
void Engine::Base::SetVolume(const uint volume) {
void EngineBase::SetVolume(const uint volume) {
volume_ = volume;
SetVolumeSW(volume);
}
void Engine::Base::ReloadSettings() {
void EngineBase::ReloadSettings() {
QSettings s;
@@ -190,7 +219,7 @@ void Engine::Base::ReloadSettings() {
}
void Engine::Base::EmitAboutToFinish() {
void EngineBase::EmitAboutToFinish() {
if (about_to_end_emitted_) {
return;
@@ -202,7 +231,7 @@ void Engine::Base::EmitAboutToFinish() {
}
bool Engine::Base::ValidOutput(const QString &output) {
bool EngineBase::ValidOutput(const QString &output) {
Q_UNUSED(output);

View File

@@ -38,25 +38,54 @@
#include <QString>
#include <QUrl>
#include "engine_fwd.h"
#include "enginetype.h"
#include "devicefinders.h"
#include "enginemetadata.h"
#include "core/song.h"
namespace Engine {
struct SimpleMetaBundle;
using Scope = std::vector<int16_t>;
class Base : public QObject {
class EngineBase : public QObject {
Q_OBJECT
protected:
Base(const EngineType type = EngineType::None, QObject *parent = nullptr);
EngineBase(QObject *parent = nullptr);
public:
~Base() override;
~EngineBase() override;
enum class Type {
None,
GStreamer,
VLC,
Xine
};
// State:
// Playing when playing,
// Paused when paused
// Idle when you still have a URL loaded (ie you have not been told to stop())
// Empty when you have been told to stop(),
// Error when an error occurred and you stopped yourself
//
// It is vital to be Idle just after the track has ended!
enum class State {
Empty,
Idle,
Playing,
Paused,
Error
};
enum TrackChangeType {
// One of:
First = 0x01,
Manual = 0x02,
Auto = 0x04,
Intro = 0x08,
// Any of:
SameAlbum = 0x10
};
Q_DECLARE_FLAGS(TrackChangeFlags, TrackChangeType)
struct OutputDetails {
QString name;
@@ -65,6 +94,13 @@ class Base : public QObject {
};
using OutputDetailsList = QList<OutputDetails>;
using Scope = std::vector<int16_t>;
static Type TypeFromName(const QString &name);
static QString Name(const Type type);
static QString Description(const Type type);
virtual Type type() const = 0;
virtual bool Init() = 0;
virtual State state() const = 0;
virtual void StartPreloading(const QUrl&, const QUrl&, const bool, const qint64, const qint64) {}
@@ -105,9 +141,7 @@ class Base : public QObject {
void EmitAboutToFinish();
public:
// Simple accessors
EngineType type() const { return type_; }
bool volume_control() const { return volume_control_; }
inline uint volume() const { return volume_; }
@@ -145,16 +179,15 @@ class Base : public QObject {
// Emitted when Engine successfully started playing a song with the given QUrl.
void ValidSongRequested(const QUrl &url);
void MetaData(const Engine::SimpleMetaBundle &bundle);
void MetaData(const EngineMetadata &metadata);
// Signals that the engine's state has changed (a stream was stopped for example).
// 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(const Engine::State state);
void StateChanged(const State state);
void VolumeChanged(const uint volume);
protected:
EngineType type_;
bool volume_control_;
uint volume_;
quint64 beginning_nanosec_;
@@ -208,38 +241,13 @@ class Base : public QObject {
bool strict_ssl_enabled_;
bool about_to_end_emitted_;
Q_DISABLE_COPY(Base)
Q_DISABLE_COPY(EngineBase)
};
struct SimpleMetaBundle {
SimpleMetaBundle() : type(Type::Any), length(-1), year(-1), track(-1), filetype(Song::FileType::Unknown), samplerate(-1), bitdepth(-1), bitrate(-1) {}
enum class Type {
Any,
Current,
Next
};
Type type;
QUrl media_url;
QUrl stream_url;
QString title;
QString artist;
QString album;
QString comment;
QString genre;
qint64 length;
int year;
int track;
Song::FileType filetype;
int samplerate;
int bitdepth;
int bitrate;
QString lyrics;
};
} // namespace Engine
Q_DECLARE_METATYPE(EngineBase::Type);
Q_DECLARE_METATYPE(EngineBase::State)
Q_DECLARE_METATYPE(EngineBase::TrackChangeType)
Q_DECLARE_METATYPE(EngineBase::OutputDetails)
Q_DECLARE_METATYPE(Engine::SimpleMetaBundle)
#endif // ENGINEBASE_H

View File

@@ -0,0 +1,31 @@
/*
* Strawberry Music Player
* Copyright 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "enginemetadata.h"
#include "core/song.h"
EngineMetadata::EngineMetadata()
: type(Type::Any),
length(-1),
year(-1),
track(-1),
filetype(Song::FileType::Unknown),
samplerate(-1),
bitdepth(-1),
bitrate(-1) {}

View File

@@ -0,0 +1,56 @@
/*
* Strawberry Music Player
* Copyright 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ENGINEMETADATA_H
#define ENGINEMETADATA_H
#include <QMetaType>
#include <QString>
#include <QUrl>
#include "core/song.h"
class EngineMetadata {
public:
EngineMetadata();
enum class Type {
Any,
Current,
Next
};
Type type;
QUrl media_url;
QUrl stream_url;
QString title;
QString artist;
QString album;
QString comment;
QString genre;
qint64 length;
int year;
int track;
Song::FileType filetype;
int samplerate;
int bitdepth;
int bitrate;
QString lyrics;
};
Q_DECLARE_METATYPE(EngineMetadata)
#endif // ENGINEMETADATA_H

View File

@@ -1,54 +0,0 @@
/*
* Strawberry Music Player
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <QString>
#include "enginetype.h"
namespace Engine {
Engine::EngineType EngineTypeFromName(const QString &enginename) {
QString lower = enginename.toLower();
if (lower == "gstreamer") return Engine::EngineType::GStreamer;
else if (lower == "vlc") return Engine::EngineType::VLC;
else return Engine::EngineType::None;
}
QString EngineName(const Engine::EngineType enginetype) {
switch (enginetype) {
case Engine::EngineType::GStreamer: return QString("gstreamer");
case Engine::EngineType::VLC: return QString("vlc");
case Engine::EngineType::None:
default: return QString("None");
}
}
QString EngineDescription(Engine::EngineType enginetype) {
switch (enginetype) {
case Engine::EngineType::GStreamer: return QString("GStreamer");
case Engine::EngineType::VLC: return QString("VLC");
case Engine::EngineType::None:
default: return QString("None");
}
}
} // namespace Engine

View File

@@ -1,45 +0,0 @@
/*
* Strawberry Music Player
* Copyright 2013-2021, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ENGINETYPE_H
#define ENGINETYPE_H
#include "config.h"
#include <QMetaType>
#include <QString>
namespace Engine {
enum class EngineType {
None,
GStreamer,
VLC,
Xine
};
Engine::EngineType EngineTypeFromName(const QString &enginename);
QString EngineName(const Engine::EngineType enginetype);
QString EngineDescription(const Engine::EngineType enginetype);
} // namespace Engine
Q_DECLARE_METATYPE(Engine::EngineType)
#endif // ENGINETYPE_H

View File

@@ -52,10 +52,10 @@
#include "core/signalchecker.h"
#include "utilities/timeconstants.h"
#include "enginebase.h"
#include "enginetype.h"
#include "gstengine.h"
#include "gstenginepipeline.h"
#include "gstbufferconsumer.h"
#include "enginemetadata.h"
const char *GstEngine::kAutoSink = "autoaudiosink";
const char *GstEngine::kALSASink = "alsasink";
@@ -75,7 +75,7 @@ const qint64 GstEngine::kPreloadGapNanosec = 8000 * kNsecPerMsec; // 8s
const qint64 GstEngine::kSeekDelayNanosec = 100 * kNsecPerMsec; // 100msec
GstEngine::GstEngine(TaskManager *task_manager, QObject *parent)
: Engine::Base(Engine::EngineType::GStreamer, parent),
: EngineBase(parent),
task_manager_(task_manager),
gst_startup_(nullptr),
discoverer_(nullptr),
@@ -138,21 +138,21 @@ bool GstEngine::Init() {
}
Engine::State GstEngine::state() const {
EngineBase::State GstEngine::state() const {
if (!current_pipeline_) return stream_url_.isEmpty() ? Engine::State::Empty : Engine::State::Idle;
if (!current_pipeline_) return stream_url_.isEmpty() ? EngineBase::State::Empty : EngineBase::State::Idle;
switch (current_pipeline_->state()) {
case GST_STATE_NULL:
return Engine::State::Empty;
return EngineBase::State::Empty;
case GST_STATE_READY:
return Engine::State::Idle;
return EngineBase::State::Idle;
case GST_STATE_PLAYING:
return Engine::State::Playing;
return EngineBase::State::Playing;
case GST_STATE_PAUSED:
return Engine::State::Paused;
return EngineBase::State::Paused;
default:
return Engine::State::Empty;
return EngineBase::State::Empty;
}
}
@@ -176,21 +176,21 @@ void GstEngine::StartPreloading(const QUrl &media_url, const QUrl &stream_url, c
}
bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const Engine::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) {
bool GstEngine::Load(const QUrl &media_url, const QUrl &stream_url, const EngineBase::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) {
EnsureInitialized();
Engine::Base::Load(stream_url, media_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
EngineBase::Load(stream_url, media_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
const QByteArray gst_url = FixupUrl(stream_url);
bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & Engine::TrackChangeType::Manual) || (autocrossfade_enabled_ && change & Engine::TrackChangeType::Auto) || ((crossfade_enabled_ || autocrossfade_enabled_) && change & Engine::TrackChangeType::Intro));
bool crossfade = current_pipeline_ && ((crossfade_enabled_ && change & EngineBase::TrackChangeType::Manual) || (autocrossfade_enabled_ && change & EngineBase::TrackChangeType::Auto) || ((crossfade_enabled_ || autocrossfade_enabled_) && change & EngineBase::TrackChangeType::Intro));
if (change & Engine::TrackChangeType::Auto && change & Engine::TrackChangeType::SameAlbum && !crossfade_same_album_) {
if (change & EngineBase::TrackChangeType::Auto && change & EngineBase::TrackChangeType::SameAlbum && !crossfade_same_album_) {
crossfade = false;
}
if (!crossfade && current_pipeline_ && current_pipeline_->stream_url() == stream_url && change & Engine::TrackChangeType::Auto) {
if (!crossfade && current_pipeline_ && current_pipeline_->stream_url() == stream_url && change & EngineBase::TrackChangeType::Auto) {
// We're not crossfading, and the pipeline is already playing the URI we want, so just do nothing.
return true;
}
@@ -279,7 +279,7 @@ void GstEngine::Stop(const bool stop_after) {
current_pipeline_.reset();
BufferingFinished();
emit StateChanged(Engine::State::Empty);
emit StateChanged(EngineBase::State::Empty);
}
@@ -293,7 +293,7 @@ void GstEngine::Pause() {
current_pipeline_->StartFader(fadeout_pause_duration_nanosec_, QTimeLine::Forward, QEasingCurve::InOutQuad, false);
is_fading_out_to_pause_ = false;
has_faded_out_ = false;
emit StateChanged(Engine::State::Playing);
emit StateChanged(EngineBase::State::Playing);
return;
}
@@ -303,7 +303,7 @@ void GstEngine::Pause() {
}
else {
current_pipeline_->SetState(GST_STATE_PAUSED);
emit StateChanged(Engine::State::Paused);
emit StateChanged(EngineBase::State::Paused);
StopTimers();
}
}
@@ -325,7 +325,7 @@ void GstEngine::Unpause() {
has_faded_out_ = false;
}
emit StateChanged(Engine::State::Playing);
emit StateChanged(EngineBase::State::Playing);
StartTimers();
}
@@ -373,7 +373,7 @@ qint64 GstEngine::length_nanosec() const {
}
const Engine::Scope &GstEngine::scope(const int chunk_length) {
const EngineBase::Scope &GstEngine::scope(const int chunk_length) {
// The new buffer could have a different size
if (have_new_buffer_) {
@@ -448,7 +448,7 @@ bool GstEngine::ALSADeviceSupport(const QString &output) {
void GstEngine::ReloadSettings() {
Engine::Base::ReloadSettings();
EngineBase::ReloadSettings();
if (output_.isEmpty()) output_ = kAutoSink;
@@ -553,7 +553,7 @@ void GstEngine::HandlePipelineError(const int pipeline_id, const int domain, con
current_pipeline_.reset();
BufferingFinished();
emit StateChanged(Engine::State::Error);
emit StateChanged(EngineBase::State::Error);
if (
(domain == static_cast<int>(GST_RESOURCE_ERROR) && (
@@ -574,10 +574,10 @@ void GstEngine::HandlePipelineError(const int pipeline_id, const int domain, con
}
void GstEngine::NewMetaData(const int pipeline_id, const Engine::SimpleMetaBundle &bundle) {
void GstEngine::NewMetaData(const int pipeline_id, const EngineMetadata &engine_metadata) {
if (!current_pipeline_|| current_pipeline_->id() != pipeline_id) return;
emit MetaData(bundle);
emit MetaData(engine_metadata);
}
@@ -609,7 +609,7 @@ void GstEngine::FadeoutPauseFinished() {
fadeout_pause_pipeline_->SetState(GST_STATE_PAUSED);
current_pipeline_->SetState(GST_STATE_PAUSED);
emit StateChanged(Engine::State::Paused);
emit StateChanged(EngineBase::State::Paused);
StopTimers();
is_fading_out_to_pause_ = false;
@@ -664,7 +664,7 @@ void GstEngine::PlayDone(const GstStateChangeReturn ret, const quint64 offset_na
Seek(offset_nanosec);
}
emit StateChanged(Engine::State::Playing);
emit StateChanged(EngineBase::State::Playing);
// We've successfully started playing a media stream with this url
emit ValidSongRequested(stream_url_);
@@ -819,7 +819,7 @@ std::shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QUrl &media_u
if (!ret->InitFromUrl(media_url, stream_url, gst_url, end_nanosec, error)) {
ret.reset();
emit Error(error);
emit StateChanged(Engine::State::Error);
emit StateChanged(EngineBase::State::Error);
emit FatalError();
}
@@ -829,7 +829,7 @@ std::shared_ptr<GstEnginePipeline> GstEngine::CreatePipeline(const QUrl &media_u
void GstEngine::UpdateScope(const int chunk_length) {
using sample_type = Engine::Scope::value_type;
using sample_type = EngineBase::Scope::value_type;
// Prevent dbz or invalid chunk size
if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(latest_buffer_))) return;
@@ -858,10 +858,10 @@ void GstEngine::UpdateScope(const int chunk_length) {
// Make sure we don't go beyond the end of the buffer
if (scope_chunk_ == scope_chunks_ - 1) {
bytes = qMin(static_cast<Engine::Scope::size_type>(map.size - (chunk_size * scope_chunk_)), scope_.size() * sizeof(sample_type));
bytes = qMin(static_cast<EngineBase::Scope::size_type>(map.size - (chunk_size * scope_chunk_)), scope_.size() * sizeof(sample_type));
}
else {
bytes = qMin(static_cast<Engine::Scope::size_type>(chunk_size), scope_.size() * sizeof(sample_type));
bytes = qMin(static_cast<EngineBase::Scope::size_type>(chunk_size), scope_.size() * sizeof(sample_type));
}
scope_chunk_++;
@@ -908,20 +908,20 @@ void GstEngine::StreamDiscovered(GstDiscoverer*, GstDiscovererInfo *info, GError
GstDiscovererStreamInfo *stream_info = reinterpret_cast<GstDiscovererStreamInfo*>(g_list_first(audio_streams)->data);
Engine::SimpleMetaBundle bundle;
EngineMetadata engine_metadata;
if (discovered_url == instance->current_pipeline_->gst_url()) {
bundle.type = Engine::SimpleMetaBundle::Type::Current;
bundle.media_url = instance->current_pipeline_->media_url();
bundle.stream_url = instance->current_pipeline_->stream_url();
engine_metadata.type = EngineMetadata::Type::Current;
engine_metadata.media_url = instance->current_pipeline_->media_url();
engine_metadata.stream_url = instance->current_pipeline_->stream_url();
}
else if (discovered_url == instance->current_pipeline_->next_gst_url()) {
bundle.type = Engine::SimpleMetaBundle::Type::Next;
bundle.media_url = instance->current_pipeline_->next_media_url();
bundle.stream_url = instance->current_pipeline_->next_stream_url();
engine_metadata.type = EngineMetadata::Type::Next;
engine_metadata.media_url = instance->current_pipeline_->next_media_url();
engine_metadata.stream_url = instance->current_pipeline_->next_stream_url();
}
bundle.samplerate = static_cast<int>(gst_discoverer_audio_info_get_sample_rate(GST_DISCOVERER_AUDIO_INFO(stream_info)));
bundle.bitdepth = static_cast<int>(gst_discoverer_audio_info_get_depth(GST_DISCOVERER_AUDIO_INFO(stream_info)));
bundle.bitrate = static_cast<int>(gst_discoverer_audio_info_get_bitrate(GST_DISCOVERER_AUDIO_INFO(stream_info)) / 1000);
engine_metadata.samplerate = static_cast<int>(gst_discoverer_audio_info_get_sample_rate(GST_DISCOVERER_AUDIO_INFO(stream_info)));
engine_metadata.bitdepth = static_cast<int>(gst_discoverer_audio_info_get_depth(GST_DISCOVERER_AUDIO_INFO(stream_info)));
engine_metadata.bitrate = static_cast<int>(gst_discoverer_audio_info_get_bitrate(GST_DISCOVERER_AUDIO_INFO(stream_info)) / 1000);
GstCaps *caps = gst_discoverer_stream_info_get_caps(stream_info);
@@ -931,20 +931,20 @@ void GstEngine::StreamDiscovered(GstDiscoverer*, GstDiscovererInfo *info, GError
if (!gst_structure) continue;
QString mimetype = gst_structure_get_name(gst_structure);
if (!mimetype.isEmpty() && mimetype != "audio/mpeg") {
bundle.filetype = Song::FiletypeByMimetype(mimetype);
if (bundle.filetype == Song::FileType::Unknown) {
engine_metadata.filetype = Song::FiletypeByMimetype(mimetype);
if (engine_metadata.filetype == Song::FileType::Unknown) {
qLog(Error) << "Unknown mimetype" << mimetype;
}
}
}
if (bundle.filetype == Song::FileType::Unknown) {
if (engine_metadata.filetype == Song::FileType::Unknown) {
gchar *codec_description = gst_pb_utils_get_codec_description(caps);
QString filetype_description = (codec_description ? QString(codec_description) : QString());
g_free(codec_description);
if (!filetype_description.isEmpty()) {
bundle.filetype = Song::FiletypeByDescription(filetype_description);
if (bundle.filetype == Song::FileType::Unknown) {
engine_metadata.filetype = Song::FiletypeByDescription(filetype_description);
if (engine_metadata.filetype == Song::FileType::Unknown) {
qLog(Error) << "Unknown filetype" << filetype_description;
}
}
@@ -953,9 +953,9 @@ void GstEngine::StreamDiscovered(GstDiscoverer*, GstDiscovererInfo *info, GError
gst_caps_unref(caps);
gst_discoverer_stream_info_list_free(audio_streams);
qLog(Debug) << "Got stream info for" << discovered_url + ":" << Song::TextForFiletype(bundle.filetype);
qLog(Debug) << "Got stream info for" << discovered_url + ":" << Song::TextForFiletype(engine_metadata.filetype);
emit instance->MetaData(bundle);
emit instance->MetaData(engine_metadata);
}
else {

View File

@@ -39,7 +39,6 @@
#include <QUrl>
#include "utilities/timeconstants.h"
#include "engine_fwd.h"
#include "enginebase.h"
#include "gststartup.h"
#include "gstbufferconsumer.h"
@@ -49,7 +48,7 @@ class QTimerEvent;
class TaskManager;
class GstEnginePipeline;
class GstEngine : public Engine::Base, public GstBufferConsumer {
class GstEngine : public EngineBase, public GstBufferConsumer {
Q_OBJECT
public:
@@ -58,10 +57,11 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
static const char *kAutoSink;
Type type() const override { return Type::GStreamer; }
bool Init() override;
Engine::State state() const override;
EngineBase::State state() const override;
void StartPreloading(const QUrl &media_url, const QUrl &stream_url, const bool force_stop_at_end, const qint64 beginning_nanosec, const qint64 end_nanosec) override;
bool Load(const QUrl &media_url, const QUrl &stream_url, const Engine::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) override;
bool Load(const QUrl &media_url, const QUrl &stream_url, const EngineBase::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) override;
bool Play(const quint64 offset_nanosec) override;
void Stop(const bool stop_after = false) override;
void Pause() override;
@@ -74,7 +74,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
public:
qint64 position_nanosec() const override;
qint64 length_nanosec() const override;
const Engine::Scope &scope(const int chunk_length) override;
const EngineBase::Scope &scope(const int chunk_length) override;
OutputDetailsList GetOutputsList() const override;
bool ValidOutput(const QString &output) override;
@@ -111,7 +111,7 @@ class GstEngine : public Engine::Base, public GstBufferConsumer {
private slots:
void EndOfStreamReached(const int pipeline_id, const bool has_next_track);
void HandlePipelineError(const int pipeline_id, const int domain, const int error_code, const QString &message, const QString &debugstr);
void NewMetaData(const int pipeline_id, const Engine::SimpleMetaBundle &bundle);
void NewMetaData(const int pipeline_id, const EngineMetadata &engine_metadata);
void AddBufferToScope(GstBuffer *buf, const int pipeline_id, const QString &format);
void FadeoutFinished();
void FadeoutPauseFinished();

View File

@@ -1307,24 +1307,24 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
GstTagList *taglist = nullptr;
gst_message_parse_tag(msg, &taglist);
Engine::SimpleMetaBundle bundle;
bundle.type = Engine::SimpleMetaBundle::Type::Current;
bundle.media_url = media_url_;
bundle.stream_url = stream_url_;
bundle.title = ParseStrTag(taglist, GST_TAG_TITLE);
bundle.artist = ParseStrTag(taglist, GST_TAG_ARTIST);
bundle.comment = ParseStrTag(taglist, GST_TAG_COMMENT);
bundle.album = ParseStrTag(taglist, GST_TAG_ALBUM);
bundle.bitrate = static_cast<int>(ParseUIntTag(taglist, GST_TAG_BITRATE) / 1000);
bundle.lyrics = ParseStrTag(taglist, GST_TAG_LYRICS);
EngineMetadata engine_metadata;
engine_metadata.type = EngineMetadata::Type::Current;
engine_metadata.media_url = media_url_;
engine_metadata.stream_url = stream_url_;
engine_metadata.title = ParseStrTag(taglist, GST_TAG_TITLE);
engine_metadata.artist = ParseStrTag(taglist, GST_TAG_ARTIST);
engine_metadata.comment = ParseStrTag(taglist, GST_TAG_COMMENT);
engine_metadata.album = ParseStrTag(taglist, GST_TAG_ALBUM);
engine_metadata.bitrate = static_cast<int>(ParseUIntTag(taglist, GST_TAG_BITRATE) / 1000);
engine_metadata.lyrics = ParseStrTag(taglist, GST_TAG_LYRICS);
if (!bundle.title.isEmpty() && bundle.artist.isEmpty() && bundle.album.isEmpty()) {
if (!engine_metadata.title.isEmpty() && engine_metadata.artist.isEmpty() && engine_metadata.album.isEmpty()) {
QStringList title_splitted;
if (bundle.title.contains(" - ")) {
title_splitted = bundle.title.split(" - ");
if (engine_metadata.title.contains(" - ")) {
title_splitted = engine_metadata.title.split(" - ");
}
else if (bundle.title.contains('~')) {
title_splitted = bundle.title.split('~');
else if (engine_metadata.title.contains('~')) {
title_splitted = engine_metadata.title.split('~');
}
if (!title_splitted.isEmpty() && title_splitted.count() >= 2) {
int i = 0;
@@ -1332,13 +1332,13 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
++i;
switch (i) {
case 1:
bundle.artist = title_part.trimmed();
engine_metadata.artist = title_part.trimmed();
break;
case 2:
bundle.title = title_part.trimmed();
engine_metadata.title = title_part.trimmed();
break;
case 3:
bundle.album = title_part.trimmed();
engine_metadata.album = title_part.trimmed();
break;
default:
break;
@@ -1349,7 +1349,7 @@ void GstEnginePipeline::TagMessageReceived(GstMessage *msg) {
gst_tag_list_unref(taglist);
emit MetadataFound(id(), bundle);
emit MetadataFound(id(), engine_metadata);
}

View File

@@ -44,12 +44,10 @@
#include <QString>
#include <QUrl>
#include "enginemetadata.h"
class QTimerEvent;
class GstBufferConsumer;
namespace Engine {
struct SimpleMetaBundle;
} // namespace Engine
struct GstPlayBin;
class GstEnginePipeline : public QObject {
@@ -132,7 +130,7 @@ class GstEnginePipeline : public QObject {
void Error(const int pipeline_id, const int domain, const int error_code, const QString &message, const QString &debug);
void EndOfStreamReached(const int pipeline_id, const bool has_next_track);
void MetadataFound(const int pipeline_id, const Engine::SimpleMetaBundle &bundle);
void MetadataFound(const int pipeline_id, const EngineMetadata &bundle);
void VolumeChanged(const uint volume);
void FaderFinished();

View File

@@ -32,17 +32,15 @@
#include "core/taskmanager.h"
#include "core/logging.h"
#include "utilities/timeconstants.h"
#include "engine_fwd.h"
#include "enginebase.h"
#include "enginetype.h"
#include "vlcengine.h"
#include "vlcscopedref.h"
VLCEngine::VLCEngine(TaskManager *task_manager, QObject *parent)
: Engine::Base(Engine::EngineType::VLC, parent),
: EngineBase(parent),
instance_(nullptr),
player_(nullptr),
state_(Engine::State::Empty) {
state_(State::Empty) {
Q_UNUSED(task_manager);
@@ -52,7 +50,7 @@ VLCEngine::VLCEngine(TaskManager *task_manager, QObject *parent)
VLCEngine::~VLCEngine() {
if (state_ == Engine::State::Playing || state_ == Engine::State::Paused) {
if (state_ == State::Playing || state_ == State::Paused) {
libvlc_media_player_stop(player_);
}
@@ -100,7 +98,7 @@ bool VLCEngine::Init() {
}
bool VLCEngine::Load(const QUrl &media_url, const QUrl &stream_url, const Engine::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) {
bool VLCEngine::Load(const QUrl &media_url, const QUrl &stream_url, const EngineBase::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) {
Q_UNUSED(media_url);
Q_UNUSED(change);
@@ -197,7 +195,7 @@ void VLCEngine::SetVolumeSW(const uint percent) {
qint64 VLCEngine::position_nanosec() const {
if (state_ == Engine::State::Empty) return 0;
if (state_ == State::Empty) return 0;
const qint64 result = (position() * kNsecPerMsec);
return qMax(0LL, result);
@@ -205,7 +203,7 @@ qint64 VLCEngine::position_nanosec() const {
qint64 VLCEngine::length_nanosec() const {
if (state_ == Engine::State::Empty) return 0;
if (state_ == State::Empty) return 0;
const qint64 result = (end_nanosec_ - static_cast<qint64>(beginning_nanosec_));
if (result > 0) {
return result;
@@ -297,32 +295,32 @@ void VLCEngine::StateChangedCallback(const libvlc_event_t *e, void *data) {
break;
case libvlc_MediaPlayerStopped:{
const Engine::State state = engine->state_;
engine->state_ = Engine::State::Empty;
if (state == Engine::State::Playing) {
const EngineBase::State state = engine->state_;
engine->state_ = EngineBase::State::Empty;
if (state == EngineBase::State::Playing) {
emit engine->StateChanged(engine->state_);
}
break;
}
case libvlc_MediaPlayerEncounteredError:
engine->state_ = Engine::State::Error;
engine->state_ = EngineBase::State::Error;
emit engine->StateChanged(engine->state_);
emit engine->FatalError();
break;
case libvlc_MediaPlayerPlaying:
engine->state_ = Engine::State::Playing;
engine->state_ = EngineBase::State::Playing;
emit engine->StateChanged(engine->state_);
break;
case libvlc_MediaPlayerPaused:
engine->state_ = Engine::State::Paused;
engine->state_ = EngineBase::State::Paused;
emit engine->StateChanged(engine->state_);
break;
case libvlc_MediaPlayerEndReached:
engine->state_ = Engine::State::Idle;
engine->state_ = EngineBase::State::Idle;
emit engine->TrackEnded();
break;
}

View File

@@ -31,23 +31,23 @@
#include <QString>
#include <QUrl>
#include "engine_fwd.h"
#include "enginebase.h"
struct libvlc_event_t;
class TaskManager;
class VLCEngine : public Engine::Base {
class VLCEngine : public EngineBase {
Q_OBJECT
public:
explicit VLCEngine(TaskManager *task_manager, QObject *parent = nullptr);
~VLCEngine() override;
Type type() const override { return Type::VLC; }
bool Init() override;
Engine::State state() const override { return state_; }
bool Load(const QUrl &media_url, const QUrl &stream_url, const Engine::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) override;
EngineBase::State state() const override { return state_; }
bool Load(const QUrl &media_url, const QUrl &stream_url, const EngineBase::TrackChangeFlags change, const bool force_stop_at_end, const quint64 beginning_nanosec, const qint64 end_nanosec) override;
bool Play(const quint64 offset_nanosec) override;
void Stop(const bool stop_after = false) override;
void Pause() override;
@@ -70,7 +70,7 @@ class VLCEngine : public Engine::Base {
private:
libvlc_instance_t *instance_;
libvlc_media_player_t *player_;
Engine::State state_;
State state_;
bool Initialized() const { return (instance_ && player_); }
uint position() const;