1
0
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:
Arnaud Bienner 2011-08-10 00:49:36 +02:00
parent cb28557a77
commit 07ce755060
3 changed files with 40 additions and 6 deletions

View File

@ -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&)));

View File

@ -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_;

View File

@ -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.