mirror of
https://github.com/clementine-player/Clementine
synced 2024-12-17 12:02:48 +01:00
Work with multiple CD devices
This commit is contained in:
parent
cb28557a77
commit
07ce755060
@ -47,12 +47,14 @@ void CddaDevice::Init() {
|
||||
return;
|
||||
}
|
||||
// Create gstreamer cdda element
|
||||
cdda_ = gst_element_make_from_uri (GST_URI_SRC, "cdda://", unique_id_.toLocal8Bit().constData());
|
||||
cdda_ = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL);
|
||||
if (cdda_ == NULL) {
|
||||
model_->Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
GST_CDDA_BASE_SRC(cdda_)->device = g_strdup (unique_id_.toLocal8Bit().constData());
|
||||
|
||||
// Change the element's state to ready and paused, to be able to query it
|
||||
if (gst_element_set_state(cdda_, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE ||
|
||||
gst_element_set_state(cdda_, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
|
||||
@ -86,7 +88,7 @@ void CddaDevice::Init() {
|
||||
song.set_id(track_number);
|
||||
song.set_valid(true);
|
||||
song.set_filetype(Song::Type_Cdda);
|
||||
song.set_url(QUrl(QString("cdda://%1").arg(track_number)));
|
||||
song.set_url(QUrl(QString("cdda://%1/%2").arg(unique_id()).arg(track_number)));
|
||||
song.set_title(QString("Track %1").arg(track_number));
|
||||
song.set_track(track_number);
|
||||
songs << song;
|
||||
@ -146,7 +148,7 @@ void CddaDevice::AudioCDTagsLoaded(const QString& artist, const QString& album,
|
||||
song.set_id(track_number);
|
||||
song.set_track(track_number);
|
||||
// We need to set url: that's how playlist will find the correct item to update
|
||||
song.set_url(QUrl(QString("cdda://%1").arg(track_number++)));
|
||||
song.set_url(QUrl(QString("cdda://%1/%2").arg(unique_id()).arg(track_number++)));
|
||||
songs << song;
|
||||
}
|
||||
connect(this, SIGNAL(SongsDiscovered(const SongList&)), model_, SLOT(SongsDiscovered(const SongList&)));
|
||||
|
@ -153,6 +153,7 @@ bool GstEnginePipeline::ReplaceDecodeBin(const QUrl& url) {
|
||||
g_object_set(G_OBJECT(new_bin), "use-buffering", true, NULL);
|
||||
g_signal_connect(G_OBJECT(new_bin), "drained", G_CALLBACK(SourceDrainedCallback), this);
|
||||
g_signal_connect(G_OBJECT(new_bin), "pad-added", G_CALLBACK(NewPadCallback), this);
|
||||
g_signal_connect(G_OBJECT(new_bin), "notify::source", G_CALLBACK(SourceSetupCallback), this);
|
||||
return ReplaceDecodeBin(new_bin);
|
||||
}
|
||||
}
|
||||
@ -288,12 +289,23 @@ bool GstEnginePipeline::InitFromString(const QString& pipeline) {
|
||||
|
||||
bool GstEnginePipeline::InitFromUrl(const QUrl &url, qint64 end_nanosec) {
|
||||
pipeline_ = gst_pipeline_new("pipeline");
|
||||
|
||||
url_ = url;
|
||||
|
||||
if (url.scheme() == "cdda") {
|
||||
// Currently, Gstreamer can't handle input CD devices inside cdda URL. So
|
||||
// we handle them ourselve: we extract the track number and re-create an
|
||||
// URL with only cdda:// + the track number (which can be handled by
|
||||
// Gstreamer). We keep the device in mind, and we will set it later using
|
||||
// SourceSetupCallback
|
||||
QStringList path = url.path().split('/');
|
||||
url_ = QUrl(QString("cdda://%1").arg(path.takeLast()));
|
||||
source_device_ = path.join("/");
|
||||
} else {
|
||||
url_ = url;
|
||||
}
|
||||
end_offset_nanosec_ = end_nanosec;
|
||||
|
||||
// Decode bin
|
||||
if (!ReplaceDecodeBin(url)) return false;
|
||||
if (!ReplaceDecodeBin(url_)) return false;
|
||||
|
||||
return Init();
|
||||
}
|
||||
@ -560,6 +572,20 @@ void GstEnginePipeline::SourceDrainedCallback(GstURIDecodeBin* bin, gpointer sel
|
||||
}
|
||||
}
|
||||
|
||||
void GstEnginePipeline::SourceSetupCallback(GstURIDecodeBin* bin, GParamSpec *pspec, gpointer self) {
|
||||
GstEnginePipeline* instance = reinterpret_cast<GstEnginePipeline*>(self);
|
||||
GstElement* element;
|
||||
g_object_get(bin, "source", &element, NULL);
|
||||
if (element &&
|
||||
g_object_class_find_property(G_OBJECT_GET_CLASS(element), "device")) {
|
||||
// Gstreamer is not able to handle device in URL (refering to Gstreamer
|
||||
// documentation, this might be added in the future). Despite that, for now
|
||||
// we include device inside URL: we decompose it during Init and set device
|
||||
// here, when this callback is called.
|
||||
g_object_set(element, "device", instance->source_device().toLocal8Bit().constData(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void GstEnginePipeline::TransitionToNext() {
|
||||
GstElement* old_decode_bin = uridecodebin_;
|
||||
GstElement* old_tcpsrc = tcpsrc_;
|
||||
|
@ -91,6 +91,8 @@ class GstEnginePipeline : public QObject {
|
||||
|
||||
QUrl redirect_url() const { return redirect_url_; }
|
||||
|
||||
QString source_device() const { return source_device_; }
|
||||
|
||||
public slots:
|
||||
void SetVolumeModifier(qreal mod);
|
||||
|
||||
@ -114,6 +116,7 @@ class GstEnginePipeline : public QObject {
|
||||
static bool HandoffCallback(GstPad*, GstBuffer*, gpointer);
|
||||
static bool EventHandoffCallback(GstPad*, GstEvent*, gpointer);
|
||||
static void SourceDrainedCallback(GstURIDecodeBin*, gpointer);
|
||||
static void SourceSetupCallback(GstURIDecodeBin*, GParamSpec *pspec, gpointer);
|
||||
|
||||
void TagMessageReceived(GstMessage*);
|
||||
void ErrorMessageReceived(GstMessage*);
|
||||
@ -204,6 +207,9 @@ class GstEnginePipeline : public QObject {
|
||||
// callers can pick it up after the state change to PLAYING fails.
|
||||
QUrl redirect_url_;
|
||||
|
||||
// When we need to specify the device to use as source (for CD device)
|
||||
QString source_device_;
|
||||
|
||||
// Seeking while the pipeline is in the READY state doesn't work, so we have
|
||||
// to wait until it goes to PAUSED or PLAYING.
|
||||
// Also we have to wait for the decodebin to be connected.
|
||||
|
Loading…
Reference in New Issue
Block a user