Add stream discoverer to gstreamer pipeline and continuous updating of bitrate

This commit is contained in:
Jonas Kvinge
2019-09-07 23:34:13 +02:00
parent 8962644ba8
commit e45a0bf24b
33 changed files with 281 additions and 176 deletions

View File

@@ -704,6 +704,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
// Context
connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)), context_view_, SLOT(SongChanged(Song)));
connect(app_->playlist_manager(), SIGNAL(SongMetadataChanged(Song)), context_view_, SLOT(SongChanged(Song)));
connect(app_->player(), SIGNAL(PlaylistFinished()), context_view_, SLOT(Stopped()));
connect(app_->player(), SIGNAL(Playing()), context_view_, SLOT(Playing()));
connect(app_->player(), SIGNAL(Stopped()), context_view_, SLOT(Stopped()));
@@ -854,7 +855,7 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
RefreshStyleSheet();
qLog(Debug) << "Started";
qLog(Debug) << "Started" << QThread::currentThread();
initialised_ = true;
app_->scrobbler()->ConnectError();

View File

@@ -291,7 +291,7 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
case UrlHandler::LoadResult::TrackAvailable: {
qLog(Debug) << "URL handler for" << result.original_url_ << "returned" << result.media_url_;
qLog(Debug) << "URL handler for" << result.original_url_ << "returned" << result.stream_url_;
Song song;
if (is_current) song = item->Metadata();
@@ -299,14 +299,14 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
bool update(false);
// Set the media url in the temporary metadata.
// Set the stream url in the temporary metadata.
if (
(result.media_url_.isValid())
(result.stream_url_.isValid())
&&
(result.media_url_ != song.url())
(result.stream_url_ != song.url())
)
{
song.set_stream_url(result.media_url_);
song.set_stream_url(result.stream_url_);
update = true;
}
@@ -351,13 +351,13 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult &result) {
}
if (is_current) {
qLog(Debug) << "Playing song" << item->Metadata().title() << result.media_url_;
engine_->Play(result.media_url_, result.original_url_, stream_change_type_, item->Metadata().has_cue(), item->Metadata().beginning_nanosec(), item->Metadata().end_nanosec());
qLog(Debug) << "Playing song" << item->Metadata().title() << result.stream_url_;
engine_->Play(result.stream_url_, result.original_url_, stream_change_type_, item->Metadata().has_cue(), item->Metadata().beginning_nanosec(), item->Metadata().end_nanosec());
current_item_ = item;
}
else if (is_next) {
qLog(Debug) << "Preloading next song" << next_item->Metadata().title() << result.media_url_;
engine_->StartPreloading(result.media_url_, next_item->Url(), next_item->Metadata().has_cue(), next_item->Metadata().beginning_nanosec(), next_item->Metadata().end_nanosec());
qLog(Debug) << "Preloading next song" << next_item->Metadata().title() << result.stream_url_;
engine_->StartPreloading(result.stream_url_, next_item->Url(), next_item->Metadata().has_cue(), next_item->Metadata().beginning_nanosec(), next_item->Metadata().end_nanosec());
}
break;
@@ -595,7 +595,7 @@ void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle)
}
current_item_ = app_->playlist_manager()->active()->current_item();
const QUrl url = (current_item_->MediaUrl().isValid() ? current_item_->MediaUrl() : current_item_->Url());
const QUrl url = (current_item_->StreamUrl().isValid() ? current_item_->StreamUrl() : current_item_->Url());
if (url_handlers_.contains(url.scheme())) {
// It's already loading
@@ -663,32 +663,13 @@ void Player::EngineMetadataReceived(const Engine::SimpleMetaBundle &bundle) {
PlaylistItemPtr item = app_->playlist_manager()->active()->current_item();
if (!item) return;
if (bundle.url != item->Metadata().url()) return;
if (bundle.url != item->Url()) return;
Engine::SimpleMetaBundle bundle_copy = bundle;
// Maybe the metadata is from icycast and has "Artist - Title" shoved together in the title field.
const int dash_pos = bundle_copy.title.indexOf('-');
if (dash_pos != -1 && bundle_copy.artist.isEmpty()) {
// Split on " - " if it exists, otherwise split on "-".
const int space_dash_pos = bundle_copy.title.indexOf(" - ");
if (space_dash_pos != -1) {
bundle_copy.artist = bundle_copy.title.left(space_dash_pos).trimmed();
bundle_copy.title = bundle_copy.title.mid(space_dash_pos + 3).trimmed();
}
else {
bundle_copy.artist = bundle_copy.title.left(dash_pos).trimmed();
bundle_copy.title = bundle_copy.title.mid(dash_pos + 1).trimmed();
}
}
Song song = item->Metadata();
song.MergeFromSimpleMetaBundle(bundle_copy);
bool minor = song.MergeFromSimpleMetaBundle(bundle);
// Ignore useless metadata
if (song.title().isEmpty() && song.artist().isEmpty()) return;
app_->playlist_manager()->active()->SetStreamMetadata(item->Url(), song);
app_->playlist_manager()->active()->SetStreamMetadata(item->Url(), song, minor);
}
@@ -768,7 +749,7 @@ void Player::TrackAboutToEnd() {
// Crossfade is off, so start preloading the next track so we don't get a gap between songs.
if (!has_next_row || !next_item) return;
QUrl url = (next_item->MediaUrl().isValid() ? next_item->MediaUrl() : next_item->Url());
QUrl url = (next_item->StreamUrl().isValid() ? next_item->StreamUrl() : next_item->Url());
// Get the actual track URL rather than the stream URL.
if (url_handlers_.contains(url.scheme())) {
@@ -784,7 +765,7 @@ void Player::TrackAboutToEnd() {
loading_async_ << url;
return;
case UrlHandler::LoadResult::TrackAvailable:
url = result.media_url_;
url = result.stream_url_;
break;
}
}

View File

@@ -1149,28 +1149,57 @@ void Song::ToMTP(LIBMTP_track_t *track) const {
}
#endif
void Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
if (d->init_from_file_ || d->url_.scheme() == "file") {
// This Song was already loaded using taglib. Our tags are probably better than the engine's.
// Note: init_from_file_ is used for non-file:// URLs when the metadata is known to be good, like from Jamendo.
return;
}
bool Song::MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle) {
d->valid_ = true;
if (!bundle.title.isEmpty()) set_title(bundle.title);
if (!bundle.artist.isEmpty()) set_artist(bundle.artist);
if (!bundle.album.isEmpty()) set_album(bundle.album);
if (!bundle.comment.isEmpty()) d->comment_ = bundle.comment;
if (!bundle.genre.isEmpty()) d->genre_ = bundle.genre;
bool minor = true;
if (d->init_from_file_ || is_collection_song() || d->url_.isLocalFile()) {
// This Song was already loaded using taglib. Our tags are probably better than the engine's.
if (title() != bundle.title && title().isEmpty() && !bundle.title.isEmpty()) {
set_title(bundle.title);
minor = false;
}
if (artist() != bundle.artist && artist().isEmpty() && !bundle.artist.isEmpty()) {
set_artist(bundle.artist);
minor = false;
}
if (album() != bundle.album && album().isEmpty() && !bundle.album.isEmpty()) {
set_album(bundle.album);
minor = false;
}
if (comment().isEmpty() && !bundle.comment.isEmpty()) set_comment(bundle.comment);
if (genre().isEmpty() && !bundle.genre.isEmpty()) set_genre(bundle.genre);
if (lyrics().isEmpty() && !bundle.lyrics.isEmpty()) set_lyrics(bundle.lyrics);
}
else {
if (title() != bundle.title && !bundle.title.isEmpty()) {
set_title(bundle.title);
minor = false;
}
if (artist() != bundle.artist && !bundle.artist.isEmpty()) {
set_artist(bundle.artist);
minor = false;
}
if (album() != bundle.album && !bundle.album.isEmpty()) {
set_album(bundle.album);
minor = false;
}
if (!bundle.comment.isEmpty()) set_comment(bundle.comment);
if (!bundle.genre.isEmpty()) set_genre(bundle.genre);
if (!bundle.lyrics.isEmpty()) set_lyrics(bundle.lyrics);
}
if (bundle.length > 0) set_length_nanosec(bundle.length);
if (bundle.year > 0) d->year_ = bundle.year;
if (bundle.track > 0) d->track_ = bundle.track;
if (bundle.filetype != FileType_Unknown) d->filetype_ = bundle.filetype;
if (bundle.samplerate > 0) d->samplerate_ = bundle.samplerate;
if (bundle.bitdepth > 0) d->samplerate_ = bundle.bitdepth;
if (bundle.bitdepth > 0) d->bitdepth_ = bundle.bitdepth;
if (bundle.bitrate > 0) d->bitrate_ = bundle.bitrate;
if (!bundle.lyrics.isEmpty()) d->lyrics_ = bundle.lyrics;
return minor;
}

View File

@@ -156,7 +156,7 @@ class Song {
void InitFromFilePartial(const QString &filename); // Just store the filename: incomplete but fast
void InitArtManual(); // Check if there is already a art in the cache and store the filename in art_manual
void MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle);
bool MergeFromSimpleMetaBundle(const Engine::SimpleMetaBundle &bundle);
#ifdef HAVE_LIBGPOD
void InitFromItdb(const _Itdb_Track *track, const QString &prefix);

View File

@@ -28,10 +28,10 @@
#include "song.h"
#include "urlhandler.h"
UrlHandler::LoadResult::LoadResult(const QUrl &original_url, const Type type, const QUrl &media_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 length_nanosec, const QString error) :
UrlHandler::LoadResult::LoadResult(const QUrl &original_url, const Type type, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 length_nanosec, const QString error) :
original_url_(original_url),
type_(type),
media_url_(media_url),
stream_url_(stream_url),
filetype_(filetype),
samplerate_(samplerate),
bit_depth_(bit_depth),

View File

@@ -50,14 +50,14 @@ class UrlHandler : public QObject {
// AsyncLoadComplete will be emitted later with the same original_url.
WillLoadAsynchronously,
// There was a track available. Its url is in media_url.
// There was a track available. Its url is in stream_url.
TrackAvailable,
// There was a error
Error,
};
LoadResult(const QUrl &original_url = QUrl(), const Type type = NoMoreTracks, const QUrl &media_url = QUrl(), const Song::FileType filetype = Song::FileType_Stream, const int samplerate = -1, const int bitdepth = -1, const qint64 length_nanosec_ = -1, const QString error = QString());
LoadResult(const QUrl &original_url = QUrl(), const Type type = NoMoreTracks, const QUrl &stream_url = QUrl(), const Song::FileType filetype = Song::FileType_Stream, const int samplerate = -1, const int bitdepth = -1, const qint64 length_nanosec_ = -1, const QString error = QString());
// The url that the playlist item has in Url().
// Might be something unplayable like lastfm://...
@@ -66,7 +66,7 @@ class UrlHandler : public QObject {
Type type_;
// The actual url to something that gstreamer can play.
QUrl media_url_;
QUrl stream_url_;
// The type of the stream
Song::FileType filetype_;