Work on other approach.
This commit is contained in:
parent
341d5d3722
commit
8ab13d2b23
|
@ -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;
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ class MediaPipeline {
|
|||
|
||||
void WriteData(const char* data, qint64 length);
|
||||
void EndStream();
|
||||
void SendEvent();
|
||||
|
||||
int port() const { return port_; }
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue