Add stream discoverer to gstreamer pipeline and continuous updating of bitrate
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user