Almost. SpotifyClient streams new tracks to a new media pipeline.

Bugs:
- If the transition work, there is no audio output, but the pipeline is filled with data.
- Sometimes the transition doesn't work and a complete new gstpipeline is created. Not sure why yet.
This commit is contained in:
Andreas 2015-04-14 16:33:44 +02:00
parent c62cc10759
commit a1855f84bc
7 changed files with 37 additions and 35 deletions

View File

@ -41,7 +41,11 @@ MediaPipeline::~MediaPipeline() {
}
bool MediaPipeline::Init(int sample_rate, int channels) {
if (is_initialised()) return false;
qLog(Debug) << "MediaPipeline::Init";
if (is_initialised()) {
qLog(Debug) << "is_initialised() true";
return false;
}
pipeline_ = gst_pipeline_new("pipeline");
@ -51,6 +55,7 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
tcpsink_ = gst_element_factory_make("tcpclientsink", nullptr);
if (!pipeline_ || !appsrc_ || !tcpsink_) {
qLog(Debug) << "!pipeline_ || !appsrc_ || !tcpsink_";
if (pipeline_) {
gst_object_unref(GST_OBJECT(pipeline_));
qLog(Debug) << "have pipeline_";

View File

@ -775,6 +775,7 @@ void SpotifyClient::MetadataUpdatedCallback(sp_session* session) {
}
void SpotifyClient::ContinueGaplessPlayback(const PrefetchTrackRequest& req) {
qLog(Debug) << "ContinueGaplessPlayback" << gapless_playback_;
if (!gapless_playback_)
return;
@ -787,9 +788,9 @@ void SpotifyClient::ContinueGaplessPlayback(const PrefetchTrackRequest& req) {
sp_error error = sp_session_player_load(session_, req.track_);
qLog(Debug) << Q_FUNC_INFO << sp_error_message(error);
//int port = media_pipeline_->port();
//media_pipeline_.reset(new MediaPipeline(port,
// sp_track_duration(req.track_)));
qLog(Debug) << "EndOfTrackCallback - new pipeline";
media_pipeline_.reset(media_pipeline_prefetch_);
media_pipeline_prefetch_ = nullptr;
error = sp_session_player_play(session_, true);
qLog(Debug) << Q_FUNC_INFO << sp_error_message(error);
@ -855,14 +856,13 @@ void SpotifyClient::EndOfTrackCallback(sp_session* session) {
if (me->gapless_playback_ && !me->prefetched_tracks_.isEmpty()) {
for (const PrefetchTrackRequest req : me->prefetched_tracks_.values()) {
qLog(Debug) << "EndOfTrackCallback - something prefetched";
if (me->gapless_playback_ && me->media_pipeline_prefetch_) {
qLog(Debug) << "EndOfTrackCallback - new pipeline";
me->media_pipeline_.reset(me->media_pipeline_prefetch_);
me->media_pipeline_prefetch_ = nullptr;
me->ContinueGaplessPlayback(req);
}
}
} else {
qLog(Debug) << "EndOfTrackCallback - reset";
me->media_pipeline_.reset();
}
}
@ -970,6 +970,7 @@ int SpotifyClient::GetDownloadProgress(sp_playlist* playlist) {
}
void SpotifyClient::StartPlayback(const pb::spotify::PlaybackRequest& req) {
qLog(Debug) << "StartPlayback";
QString uri = QString::fromStdString(req.track_uri());
// Get a link object from the URI
@ -1069,8 +1070,11 @@ void SpotifyClient::PrefetchTrack(const pb::spotify::PlaybackRequest &req) {
prefetched_tracks_.insert(uri, prefetch_request);
qLog(Debug) << "media_pipeline_prefetch_ to port" << req.media_port();
media_pipeline_prefetch_ = new MediaPipeline(req.media_port(),
sp_track_duration(track));
ContinueGaplessPlayback(prefetch_request);
}
void SpotifyClient::SendPlaybackError(const QString& error) {

View File

@ -369,10 +369,14 @@ bool GstEngine::Load(const QUrl& url, Engine::TrackChangeFlags change,
!crossfade_same_album_)
crossfade = false;
if (current_pipeline_)
qLog(Debug) << !crossfade << "true" << (current_pipeline_->url() == gst_url) <<
(change & Engine::Auto);
if (!crossfade && current_pipeline_ && current_pipeline_->url() == gst_url &&
change & Engine::Auto) {
// We're not crossfading, and the pipeline is already playing the URI we
// want, so just do nothing.
qLog(Debug) << "do nothing";
return true;
}
@ -650,7 +654,7 @@ void GstEngine::timerEvent(QTimerEvent* e) {
const qint64 remaining = current_length - current_position;
const qint64 fudge =
kTimerIntervalNanosec + 100 * kNsecPerMsec; // Mmm fudge
kTimerIntervalNanosec + 2500 * kNsecPerMsec; // Mmm fudge
const qint64 gap = buffer_duration_nanosec_ +
(autocrossfade_enabled_ ? fadeout_duration_nanosec_
: kPreloadGapNanosec);
@ -699,11 +703,11 @@ void GstEngine::EndOfStreamReached(int pipeline_id, bool has_next_track) {
if (!current_pipeline_.get() || current_pipeline_->id() != pipeline_id)
return;
qLog(Debug) << "EndOfStreamReached" << pipeline_id << has_next_track;
if (!has_next_track) {
current_pipeline_.reset();
BufferingFinished();
} else {
current_pipeline_->SpotifyMovedToNextTrack();
}
emit TrackEnded();
}

View File

@ -154,11 +154,10 @@ bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
uridecodebin_next_spotify_ = nullptr;
} else {
new_bin = NewSpotifyBin();
// Tell spotify to start sending data to us.
InternetModel::Service<SpotifyService>()->server()->StartPlaybackLater(
url.toString(), spotify_port_);
}
// Tell spotify to start sending data to us.
InternetModel::Service<SpotifyService>()->server()->StartPlaybackLater(
url.toString(), spotify_port_);
} else {
new_bin = engine_->CreateElement("uridecodebin");
g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(),
@ -194,6 +193,8 @@ GstElement* GstEnginePipeline::NewSpotifyBin() {
gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
gst_object_unref(GST_OBJECT(pad));
qDebug() << "NewSpotifyBin done";
return new_bin;
}
@ -500,12 +501,13 @@ GstBusSyncReply GstEnginePipeline::BusCallbackSync(GstBus*, GstMessage* msg,
gpointer self) {
GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
qLog(Debug) << instance->id() << "sync bus message"
<< GST_MESSAGE_TYPE_NAME(msg);
//qLog(Debug) << instance->id() << "sync bus message"
// << GST_MESSAGE_TYPE_NAME(msg);
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_EOS:
if (instance->has_next_valid_url()) {
qDebug() << "TransitionToNext from EOS";
QMetaObject::invokeMethod(instance, "TransitionToNext", Qt::QueuedConnection);
} else {
emit instance->EndOfStreamReached(instance->id(), instance->has_next_valid_url());
@ -950,6 +952,7 @@ void GstEnginePipeline::SourceSetupCallback(GstURIDecodeBin* bin,
}
void GstEnginePipeline::TransitionToNext() {
qLog(Debug) << "TransitionToNext";
GstElement* old_decode_bin = uridecodebin_;
ignore_tags_ = true;
@ -1191,20 +1194,7 @@ void GstEnginePipeline::SetNextUrl(const QUrl& url, qint64 beginning_nanosec,
SpotifyService* spotify = InternetModel::Service<SpotifyService>();
QMetaObject::invokeMethod(spotify, "SetNextUrl", Qt::QueuedConnection,
Q_ARG(QUrl, url), Q_ARG(int, spotify_port_));
TransitionToNext();
}
}
void GstEnginePipeline::SpotifyMovedToNextTrack() {
url_ = next_url_;
end_offset_nanosec_ = next_end_offset_nanosec_;
next_url_ = QUrl();
next_beginning_offset_nanosec_ = 0;
next_end_offset_nanosec_ = 0;
// This function gets called when the source has been drained, even if the
// song hasn't finished playing yet. We'll get a new stream when it really
// does finish, so emit TrackEnded then.
emit_track_ended_on_stream_start_ = true;
gst_element_seek_simple(pipeline_, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0);
}

View File

@ -83,7 +83,6 @@ class GstEnginePipeline : public QObject {
qint64 end_nanosec);
bool has_next_valid_url() const { return next_url_.isValid(); }
QUrl next_url() const { return next_url_; }
void SpotifyMovedToNextTrack();
// Get information about the music playback
QUrl url() const { return url_; }

View File

@ -39,7 +39,7 @@ SpotifyServer::SpotifyServer(QObject* parent)
}
void SpotifyServer::Init() {
if (!server_->listen(QHostAddress::LocalHost, 56154)) {
if (!server_->listen(QHostAddress::LocalHost)) {
qLog(Error) << "Couldn't open server socket" << server_->errorString();
}
}

View File

@ -354,8 +354,8 @@ void SpotifyService::StartBlobProcess() {
SLOT(BlobProcessError(QProcess::ProcessError)));
qLog(Info) << "Starting" << blob_path;
//blob_process_->start(
// blob_path, QStringList() << QString::number(server_->server_port()));
blob_process_->start(
blob_path, QStringList() << QString::number(server_->server_port()));
}
bool SpotifyService::IsBlobInstalled() const {