Work on other approach.

This commit is contained in:
Andreas 2015-04-05 12:07:55 +02:00 committed by Andreas
parent 341d5d3722
commit 8ab13d2b23
12 changed files with 79 additions and 59 deletions

View File

@ -53,17 +53,21 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
if (!pipeline_ || !appsrc_ || !tcpsink_) {
if (pipeline_) {
gst_object_unref(GST_OBJECT(pipeline_));
qLog(Debug) << "have pipeline_";
pipeline_ = nullptr;
}
if (appsrc_) {
gst_object_unref(GST_OBJECT(appsrc_));
qLog(Debug) << "have appsrc_";
appsrc_ = nullptr;
}
if (gdppay) {
gst_object_unref(GST_OBJECT(gdppay));
qLog(Debug) << "have gdppay";
}
if (tcpsink_) {
gst_object_unref(GST_OBJECT(tcpsink_));
qLog(Debug) << "have tcpsink_";
tcpsink_ = nullptr;
}
return false;
@ -116,7 +120,7 @@ bool MediaPipeline::Init(int sample_rate, int channels) {
// Set size
byte_rate_ = quint64(sample_rate) * channels * 2;
const quint64 bytes = -1; //byte_rate_ * length_msec_ / 1000;
const quint64 bytes = byte_rate_ * length_msec_ / 1000;
gst_app_src_set_size(appsrc_, bytes);
// Ready to go
@ -143,12 +147,6 @@ void MediaPipeline::WriteData(const char* data, qint64 length) {
gst_app_src_push_buffer(appsrc_, buffer);
}
void MediaPipeline::SendEvent() {
GstTagList* list = gst_tag_list_new_empty();
GstEvent* tag = gst_event_new_tag(list);
gst_element_send_event(pipeline_, tag);
}
void MediaPipeline::EndStream() {
if (!is_initialised()) return;

View File

@ -37,7 +37,6 @@ class MediaPipeline {
void WriteData(const char* data, qint64 length);
void EndStream();
void SendEvent();
int port() const { return port_; }

View File

@ -851,9 +851,16 @@ void SpotifyClient::EndOfTrackCallback(sp_session* session) {
SpotifyClient* me =
reinterpret_cast<SpotifyClient*>(sp_session_userdata(session));
qLog(Debug) << "EndOfTrackCallback";
if (me->gapless_playback_ && !me->prefetched_tracks_.isEmpty()) {
for (const PrefetchTrackRequest req : me->prefetched_tracks_.values()) {
me->ContinueGaplessPlayback(req);
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 {
me->media_pipeline_.reset();
@ -1030,7 +1037,7 @@ void SpotifyClient::TryPlaybackAgain(const PendingPlaybackRequest& req) {
pending_playback_requests_.removeAll(req);
}
void SpotifyClient::PrefetchTrack(const pb::spotify::PrefetchRequest &req) {
void SpotifyClient::PrefetchTrack(const pb::spotify::PlaybackRequest &req) {
// Get a link object from the URI
sp_link* link = sp_link_create_from_string(req.track_uri().c_str());
if (!link) {
@ -1062,8 +1069,8 @@ void SpotifyClient::PrefetchTrack(const pb::spotify::PrefetchRequest &req) {
prefetched_tracks_.insert(uri, prefetch_request);
qDebug() << "Sending event";
media_pipeline_->SendEvent();
media_pipeline_prefetch_ = new MediaPipeline(req.media_port(),
sp_track_duration(track));
}
void SpotifyClient::SendPlaybackError(const QString& error) {

View File

@ -132,7 +132,7 @@ class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
void BrowseToplist(const pb::spotify::BrowseToplistRequest& req);
void SetPlaybackSettings(const pb::spotify::PlaybackSettings& req);
void SetPaused(const pb::spotify::PauseRequest& req);
void PrefetchTrack(const pb::spotify::PrefetchRequest& req);
void PrefetchTrack(const pb::spotify::PlaybackRequest& req);
void SendPlaylistList();
@ -210,6 +210,7 @@ class SpotifyClient : public AbstractMessageHandler<pb::spotify::Message> {
QMap<sp_albumbrowse*, sp_search*> pending_search_album_browse_responses_;
QScopedPointer<MediaPipeline> media_pipeline_;
MediaPipeline* media_pipeline_prefetch_;
};
#endif // SPOTIFYCLIENT_H

View File

@ -108,10 +108,6 @@ message PlaybackRequest {
required int32 media_port = 2;
}
message PrefetchRequest {
required string track_uri = 1;
}
message PlaybackError {
required string error = 1;
}
@ -237,5 +233,5 @@ message Message {
// ID 22 unused.
optional AddTracksToPlaylistRequest add_tracks_to_playlist = 23;
optional RemoveTracksFromPlaylistRequest remove_tracks_from_playlist = 24;
optional PrefetchRequest prefetch_request = 25;
optional PlaybackRequest prefetch_request = 25;
}

View File

@ -657,12 +657,6 @@ void GstEngine::timerEvent(QTimerEvent* e) {
// only if we know the length of the current stream...
if (current_length > 0) {
if (remaining < 0) {
qDebug() << "Remaning 0" << current_pipeline_->has_next_valid_url();
EndOfStreamReached(current_pipeline_->id(), current_pipeline_->has_next_valid_url());
//current_pipeline_->SpotifyMovedToNextTrack();
return;
}
// emit TrackAboutToEnd when we're a few seconds away from finishing
if (remaining < gap + fudge) {
EmitAboutToEnd();

View File

@ -79,6 +79,7 @@ GstEnginePipeline::GstEnginePipeline(GstEngine* engine)
volume_modifier_(1.0),
pipeline_(nullptr),
uridecodebin_(nullptr),
uridecodebin_next_spotify_(nullptr),
audiobin_(nullptr),
queue_(nullptr),
audioconvert_(nullptr),
@ -89,7 +90,8 @@ GstEnginePipeline::GstEnginePipeline(GstEngine* engine)
stereo_panorama_(nullptr),
volume_(nullptr),
audioscale_(nullptr),
audiosink_(nullptr) {
audiosink_(nullptr),
spotify_port_(0) {
if (!sElementDeleter) {
sElementDeleter = new GstElementDeleter;
}
@ -147,29 +149,16 @@ bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
GstElement* new_bin = nullptr;
if (url.scheme() == "spotify") {
new_bin = gst_bin_new("spotify_bin");
// Create elements
GstElement* src = engine_->CreateElement("tcpserversrc", new_bin);
GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin);
if (!src || !gdp) return false;
// Pick a port number
const int port = Utilities::PickUnusedPort();
g_object_set(G_OBJECT(src), "host", "127.0.0.1", nullptr);
g_object_set(G_OBJECT(src), "port", port, nullptr);
// Link the elements
gst_element_link(src, gdp);
// Add a ghost pad
GstPad* pad = gst_element_get_static_pad(gdp, "src");
gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
gst_object_unref(GST_OBJECT(pad));
if (uridecodebin_next_spotify_) {
new_bin = uridecodebin_next_spotify_;
uridecodebin_next_spotify_ = nullptr;
} else {
new_bin = NewSpotifyBin();
}
// Tell spotify to start sending data to us.
InternetModel::Service<SpotifyService>()->server()->StartPlaybackLater(
url.toString(), port);
url.toString(), spotify_port_);
} else {
new_bin = engine_->CreateElement("uridecodebin");
g_object_set(G_OBJECT(new_bin), "uri", url.toEncoded().constData(),
@ -184,6 +173,30 @@ bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
return ReplaceDecodeBin(new_bin);
}
GstElement* GstEnginePipeline::NewSpotifyBin() {
GstElement* new_bin = gst_bin_new("spotify_bin");
// Create elements
GstElement* src = engine_->CreateElement("tcpserversrc", new_bin);
GstElement* gdp = engine_->CreateElement("gdpdepay", new_bin);
if (!src || !gdp) return nullptr;
// Pick a port number
spotify_port_ = Utilities::PickUnusedPort();
g_object_set(G_OBJECT(src), "host", "127.0.0.1", nullptr);
g_object_set(G_OBJECT(src), "port", spotify_port_, nullptr);
// Link the elements
gst_element_link(src, gdp);
// Add a ghost pad
GstPad* pad = gst_element_get_static_pad(gdp, "src");
gst_element_add_pad(GST_ELEMENT(new_bin), gst_ghost_pad_new("src", pad));
gst_object_unref(GST_OBJECT(pad));
return new_bin;
}
GstElement* GstEnginePipeline::CreateDecodeBinFromString(const char* pipeline) {
GError* error = nullptr;
GstElement* bin = gst_parse_bin_from_description(pipeline, TRUE, &error);
@ -492,7 +505,11 @@ GstBusSyncReply GstEnginePipeline::BusCallbackSync(GstBus*, GstMessage* msg,
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_EOS:
emit instance->EndOfStreamReached(instance->id(), instance->has_next_valid_url());
if (instance->has_next_valid_url()) {
QMetaObject::invokeMethod(instance, "TransitionToNext", Qt::QueuedConnection);
} else {
emit instance->EndOfStreamReached(instance->id(), instance->has_next_valid_url());
}
break;
case GST_MESSAGE_TAG:
@ -1168,9 +1185,12 @@ void GstEnginePipeline::SetNextUrl(const QUrl& url, qint64 beginning_nanosec,
next_end_offset_nanosec_ = end_nanosec;
if (url.scheme() == "spotify") {
// Call this first, then we have a new spotify_port_
uridecodebin_next_spotify_ = NewSpotifyBin();
SpotifyService* spotify = InternetModel::Service<SpotifyService>();
QMetaObject::invokeMethod(spotify, "SetNextUrl", Qt::QueuedConnection,
Q_ARG(QUrl, url));
Q_ARG(QUrl, url), Q_ARG(int, spotify_port_));
}
}

View File

@ -158,8 +158,9 @@ signals:
void UpdateStereoBalance();
bool ReplaceDecodeBin(GstElement* new_bin);
bool ReplaceDecodeBin(const QUrl& url);
GstElement* NewSpotifyBin();
void TransitionToNext();
Q_INVOKABLE void TransitionToNext();
// If the decodebin is special (ie. not really a uridecodebin) then it'll have
// a src pad immediately and we can link it after everything's created.
@ -272,6 +273,7 @@ signals:
// Bins
// uridecodebin ! audiobin
GstElement* uridecodebin_;
GstElement* uridecodebin_next_spotify_;
GstElement* audiobin_;
// Elements in the audiobin. See comments in Init()'s definition.
@ -292,6 +294,8 @@ signals:
QThreadPool set_state_threadpool_;
GstSegment last_decodebin_segment_;
int spotify_port_;
};
#endif // GSTENGINEPIPELINE_H

View File

@ -39,7 +39,7 @@ SpotifyServer::SpotifyServer(QObject* parent)
}
void SpotifyServer::Init() {
if (!server_->listen(QHostAddress::LocalHost)) {
if (!server_->listen(QHostAddress::LocalHost, 56154)) {
qLog(Error) << "Couldn't open server socket" << server_->errorString();
}
}
@ -331,9 +331,11 @@ void SpotifyServer::SetPaused(const bool paused) {
SendOrQueueMessage(message);
}
void SpotifyServer::PrefetchTrack(const QUrl& url) {
void SpotifyServer::PrefetchTrack(const QUrl& url, const int port) {
pb::spotify::Message message;
pb::spotify::PrefetchRequest* req = message.mutable_prefetch_request();
pb::spotify::PlaybackRequest* req = message.mutable_prefetch_request();
req->set_track_uri(DataCommaSizeFromQString(url.toString()));
req->set_media_port(port);
SendOrQueueMessage(message);
}

View File

@ -61,7 +61,7 @@ class SpotifyServer : public AbstractMessageHandler<pb::spotify::Message> {
bool volume_normalisation);
void LoadToplist();
void SetPaused(const bool paused);
void PrefetchTrack(const QUrl& url);
void PrefetchTrack(const QUrl& url, const int port);
int server_port() const;

View File

@ -342,7 +342,6 @@ void SpotifyService::StartBlobProcess() {
InstallBlob();
}
#endif
return;
}
@ -355,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 {
@ -873,10 +872,10 @@ void SpotifyService::SetPaused(bool paused) {
server_->SetPaused(paused);
}
void SpotifyService::SetNextUrl(const QUrl &url) {
qLog(Debug) << "Next Spotify Url" << url;
void SpotifyService::SetNextUrl(const QUrl &url, const int port) {
qLog(Debug) << "Next Spotify Url" << url << port;
EnsureServerCreated();
server_->PrefetchTrack(url);
server_->PrefetchTrack(url, port);
}
void SpotifyService::SyncPlaylistProgress(

View File

@ -83,7 +83,7 @@ class SpotifyService : public InternetService {
void Login(const QString& username, const QString& password);
Q_INVOKABLE void LoadImage(const QString& id);
Q_INVOKABLE void SetPaused(bool paused);
Q_INVOKABLE void SetNextUrl(const QUrl& url);
Q_INVOKABLE void SetNextUrl(const QUrl& url, const int port);
SpotifyServer* server() const;