Conflicts:
	src/devices/devicemanager.cpp
This commit is contained in:
John Maguire 2011-08-11 21:46:48 +02:00
commit b458c9d24c
15 changed files with 118 additions and 58 deletions

View File

@ -64,7 +64,6 @@ pkg_check_modules(PLIST libplist)
pkg_check_modules(USBMUXD libusbmuxd)
pkg_check_modules(LIBMTP libmtp>=1.0)
pkg_check_modules(INDICATEQT indicate-qt)
pkg_check_modules(ARCHIVE libarchive)
pkg_check_modules(SPOTIFY libspotify>=0.0.8)
pkg_check_modules(CDIO libcdio)
@ -75,14 +74,6 @@ if (WIN32)
find_library(QTSPARKLE_LIBRARIES qtsparkle)
endif (WIN32)
if (APPLE)
find_library(ARCHIVE_LIBRARIES archive)
find_path(ARCHIVE_INCLUDE_DIRS archive.h)
if (ARCHIVE_LIBRARIES)
set(ARCHIVE_FOUND ON)
endif (ARCHIVE_LIBRARIES)
endif (APPLE)
find_library(LASTFM_LIBRARIES lastfm)
find_path(LASTFM_INCLUDE_DIRS lastfm/ws.h)
@ -185,11 +176,11 @@ option(ENABLE_LIBGPOD "iPod classic support" ON)
option(ENABLE_IMOBILEDEVICE "iPod Touch, iPhone, iPad support" ON)
option(ENABLE_LIBMTP "MTP support" ON)
option(ENABLE_GIO "GIO backend" ON)
option(ENABLE_AUDIOCD "Audio CD support" ON)
option(ENABLE_VISUALISATIONS "Use libprojectm visualisations" ON)
option(BUNDLE_PROJECTM_PRESETS "Install Clementine's own copies of libprojectm presets - disable this if you want to use a system package instead" ON)
option(ENABLE_SOUNDMENU "Add Clementine to the Gnome sound menu" ON)
option(ENABLE_LIBLASTFM "Use liblastfm for fetching song info, scrobbling and radio streams" ON)
option(ENABLE_SCRIPTING_ARCHIVES "Enable support for loading scripts from archives (.clem or .tar.gz files)" ON)
option(ENABLE_REMOTE "Enable support for using remote controls with Clementine" OFF)
option(ENABLE_BREAKPAD "Enable crash reporting" OFF)
option(ENABLE_SPOTIFY_BLOB "Build the spotify non-GPL binary" ON)
@ -207,6 +198,10 @@ if(ENABLE_GIO AND GIO_FOUND AND NOT APPLE)
set(HAVE_GIO ON)
endif(ENABLE_GIO AND GIO_FOUND AND NOT APPLE)
if(ENABLE_AUDIOCD AND CDIO_FOUND)
set(HAVE_AUDIOCD ON)
endif(ENABLE_AUDIOCD AND CDIO_FOUND)
if(ENABLE_IMOBILEDEVICE AND IMOBILEDEVICE_FOUND AND PLIST_FOUND AND HAVE_LIBGPOD AND USBMUXD_FOUND)
set(HAVE_IMOBILEDEVICE ON)
endif(ENABLE_IMOBILEDEVICE AND IMOBILEDEVICE_FOUND AND PLIST_FOUND AND HAVE_LIBGPOD AND USBMUXD_FOUND)
@ -223,10 +218,6 @@ if(ENABLE_LIBLASTFM AND LASTFM_LIBRARIES AND LASTFM_INCLUDE_DIRS)
set(HAVE_LIBLASTFM ON)
endif(ENABLE_LIBLASTFM AND LASTFM_LIBRARIES AND LASTFM_INCLUDE_DIRS)
if(ENABLE_SCRIPTING_ARCHIVES AND ARCHIVE_FOUND)
set(HAVE_LIBARCHIVE ON)
endif(ENABLE_SCRIPTING_ARCHIVES AND ARCHIVE_FOUND)
if(ENABLE_WIIMOTEDEV AND HAVE_DBUS)
set(HAVE_WIIMOTEDEV ON)
endif(ENABLE_WIIMOTEDEV AND HAVE_DBUS)
@ -396,6 +387,7 @@ add_custom_target(uninstall
# Show a summary of what we have enabled
summary_add("Crash reporting" HAVE_BREAKPAD)
summary_add("D-Bus support" HAVE_DBUS)
summary_add("Devices: Audio CD support" HAVE_AUDIOCD)
summary_add("Devices: DeviceKit backend" HAVE_DEVICEKIT)
summary_add("Devices: iPod classic support" HAVE_LIBGPOD)
summary_add("Devices: iPod Touch, iPhone, iPad support" HAVE_IMOBILEDEVICE)
@ -403,7 +395,6 @@ summary_add("Devices: MTP support" HAVE_LIBMTP)
summary_add("Devices: GIO backend" HAVE_GIO)
summary_add("Gnome sound menu integration" HAVE_LIBINDICATE)
summary_add("Last.fm support" HAVE_LIBLASTFM)
summary_add("Scripting support: loading archives" HAVE_LIBARCHIVE)
summary_add("Spotify support: core code" HAVE_SPOTIFY)
summary_add("Spotify support: non-GPL binary helper" HAVE_SPOTIFY_BLOB)
summary_add("Visualisations" ENABLE_VISUALISATIONS)

View File

@ -106,7 +106,6 @@ Section "Clementine" Clementine
File "clementine.ico"
File "glew32.dll"
File "intl.dll"
File "libarchive.dll"
File "libcdio-12.dll"
File "libexpat-1.dll"
File "libfaac.dll"
@ -940,7 +939,6 @@ Section "Uninstall"
Delete "$INSTDIR\clementine-spotifyblob.exe"
Delete "$INSTDIR\glew32.dll"
Delete "$INSTDIR\intl.dll"
Delete "$INSTDIR\libarchive.dll"
Delete "$INSTDIR\libcdio-12.dll"
Delete "$INSTDIR\libexpat-1.dll"
Delete "$INSTDIR\libfaac.dll"

View File

@ -101,8 +101,6 @@ set(SOURCES
covers/coversearchstatisticsdialog.cpp
covers/kittenloader.cpp
devices/cddalister.cpp
devices/cddadevice.cpp
devices/connecteddevice.cpp
devices/devicedatabasebackend.cpp
devices/devicelister.cpp
@ -327,8 +325,6 @@ set(HEADERS
covers/coversearchstatisticsdialog.h
covers/kittenloader.h
devices/cddalister.h
devices/cddadevice.h
devices/connecteddevice.h
devices/devicedatabasebackend.h
devices/devicelister.h
@ -776,6 +772,15 @@ if(HAVE_GIO)
list(APPEND HEADERS devices/giolister.h)
endif(HAVE_GIO)
# CDIO backend and device
if(HAVE_AUDIOCD)
list(APPEND SOURCES devices/cddadevice.cpp)
list(APPEND SOURCES devices/cddalister.cpp)
list(APPEND HEADERS devices/cddadevice.h)
list(APPEND HEADERS devices/cddalister.h)
endif(HAVE_AUDIOCD)
# libimobiledevice backend and device
if(HAVE_IMOBILEDEVICE)
include_directories(${IMOBILEDEVICE_INCLUDE_DIRS})
@ -870,6 +875,10 @@ list(APPEND OTHER_SOURCES
devices/afcfile.h
devices/afctransfer.cpp
devices/afctransfer.h
devices/cddadevice.cpp
devices/cddadevice.h
devices/cddalister.cpp
devices/cddalister.h
devices/devicekitlister.h
devices/devicekitlister.cpp
devices/gpoddevice.cpp
@ -967,13 +976,11 @@ target_link_libraries(clementine_lib
${GSTREAMER_BASE_LIBRARIES}
${GSTREAMER_LIBRARIES}
${GSTREAMER_APP_LIBRARIES}
${GSTREAMER_CDDA_LIBRARIES}
${GSTREAMER_TAG_LIBRARIES}
${QTSINGLEAPPLICATION_LIBRARIES}
${QTSINGLECOREAPPLICATION_LIBRARIES}
${QTIOCOMPRESSOR_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${CDIO_LIBRARIES}
dl
z
)
@ -994,9 +1001,10 @@ if(HAVE_GIO)
target_link_libraries(clementine_lib ${GIO_LIBRARIES})
endif(HAVE_GIO)
if(HAVE_LIBARCHIVE)
target_link_libraries(clementine_lib ${ARCHIVE_LIBRARIES})
endif(HAVE_LIBARCHIVE)
if(HAVE_AUDIOCD)
target_link_libraries(clementine_lib ${CDIO_LIBRARIES})
target_link_libraries(clementine_lib ${GSTREAMER_CDDA_LIBRARIES})
endif(HAVE_AUDIOCD)
if(HAVE_IMOBILEDEVICE)
target_link_libraries(clementine_lib

View File

@ -21,6 +21,7 @@
#define CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}"
#cmakedefine ENABLE_VISUALISATIONS
#cmakedefine HAVE_AUDIOCD
#cmakedefine HAVE_BREAKPAD
#cmakedefine HAVE_DBUS
#cmakedefine HAVE_DEVICEKIT

View File

@ -15,6 +15,7 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "songloader.h"
#include "core/logging.h"
#include "core/song.h"
@ -35,7 +36,10 @@
#include <boost/bind.hpp>
#include <gst/cdda/gstcddabasesrc.h>
#ifdef HAVE_AUDIOCD
# include <gst/cdda/gstcddabasesrc.h>
#endif
QSet<QString> SongLoader::sRawUriSchemes;
const int SongLoader::kDefaultTimeout = 5000;
@ -102,6 +106,7 @@ SongLoader::Result SongLoader::LoadLocalPartial(const QString& filename) {
}
SongLoader::Result SongLoader::LoadAudioCD() {
#ifdef HAVE_AUDIOCD
// Create gstreamer cdda element
GstElement* cdda = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL);
if (cdda == NULL) {
@ -176,7 +181,10 @@ SongLoader::Result SongLoader::LoadAudioCD() {
gst_object_unref(GST_OBJECT(msg));
gst_object_unref(GST_OBJECT(tags));
return Success;
return Success;
#else // HAVE_AUDIOCD
return Error;
#endif
}
void SongLoader::AudioCDTagsLoaded(const QString& artist, const QString& album,

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

@ -37,8 +37,8 @@ public:
void Init();
void Refresh();
bool CopyToStorage(const MusicStorage::CopyJob&) { return true; }
bool DeleteFromStorage(const MusicStorage::DeleteJob&) { return true; }
bool CopyToStorage(const MusicStorage::CopyJob&) { return false; }
bool DeleteFromStorage(const MusicStorage::DeleteJob&) { return false; }
static QStringList url_schemes() { return QStringList() << "cdda"; }

View File

@ -16,6 +16,7 @@
*/
#include <cdio/cdio.h>
#include <QFileInfo>
#include <QMutex>
#include <QThread>
#include <QWaitCondition>
@ -76,7 +77,6 @@ QString CddaLister::MakeFriendlyName(const QString& id) {
return QString(cd_info.psz_model);
}
cdio_destroy(cdio);
return QString();
return QString("CD (") + id + ")";
}
@ -104,10 +104,10 @@ void CddaLister::Init() {
return;
}
for (; *devices != NULL; ++devices) {
if (strcmp("/dev/cdrom", *devices) == 0)
continue;
QString device(*devices);
QFileInfo device_info(device);
if (device_info.isSymLink())
continue;
#ifdef Q_OS_DARWIN
// Every track is detected as a separate device on Darwin. The raw disk looks
// like /dev/rdisk1

View File

@ -37,6 +37,7 @@ public:
quint64 DeviceCapacity(const QString& id);
quint64 DeviceFreeSpace(const QString& id);
QVariantMap DeviceHardwareInfo(const QString& id);
bool AskForScan() { return false; }
QString MakeFriendlyName(const QString&);
QList<QUrl> MakeDeviceUrls(const QString&);
void UnmountDevice(const QString&);

View File

@ -51,6 +51,10 @@ public:
virtual QVariantMap DeviceHardwareInfo(const QString& id) = 0;
virtual bool DeviceNeedsMount(const QString& id) { return false; }
// When connecting to a device for the first time, do we want an user's
// confirmation for scanning it? (by default yes)
virtual bool AskForScan() { return true; }
virtual QString MakeFriendlyName(const QString& id) = 0;
virtual QList<QUrl> MakeDeviceUrls(const QString& id) = 0;

View File

@ -27,8 +27,10 @@
#include "core/utilities.h"
#include "ui/iconloader.h"
#include "cddalister.h"
#include "cddadevice.h"
#ifdef HAVE_AUDIOCD
# include "cddalister.h"
# include "cddadevice.h"
#endif
#ifdef Q_OS_DARWIN
# include "macdevicelister.h"
@ -187,7 +189,7 @@ DeviceManager::DeviceManager(BackgroundThread<Database>* database,
connected_devices_model_->setSourceModel(this);
// CD devices are detected via the DiskArbitration framework instead on Darwin.
#ifndef Q_OS_DARWIN
#if defined(HAVE_AUDIOCD) && !defined(Q_OS_DARWIN)
AddLister(new CddaLister);
#endif
#ifdef HAVE_DEVICEKIT
@ -208,9 +210,12 @@ DeviceManager::DeviceManager(BackgroundThread<Database>* database,
AddDeviceClass<AfcDevice>();
#endif
AddDeviceClass<CddaDevice>();
AddDeviceClass<FilesystemDevice>();
#ifdef HAVE_AUDIOCD
AddDeviceClass<CddaDevice>();
#endif
#ifdef HAVE_LIBGPOD
AddDeviceClass<GPodDevice>();
#endif
@ -313,8 +318,8 @@ QVariant DeviceManager::data(const QModelIndex& index, int role) const {
if (!info.device_) {
if (info.database_id_ == -1 &&
!info.BestBackend()->lister_->DeviceNeedsMount(info.BestBackend()->unique_id_)) {
// Don't ask user if it is a CD device
if (info.device_ && !dynamic_cast<CddaDevice*>(info.device_.get())) {
if (info.BestBackend()->lister_->AskForScan()) {
boost::scoped_ptr<QMessageBox> dialog(new QMessageBox(
QMessageBox::Information, tr("Connect device"),
tr("This is the first time you have connected this device. Clementine will now scan the device to find music files - this may take some time."),

View File

@ -16,6 +16,7 @@
*/
#include "connecteddevice.h"
#include "devicelister.h"
#include "devicemanager.h"
#include "deviceproperties.h"
#include "deviceview.h"
@ -306,18 +307,21 @@ void DeviceView::DeviceDisconnected(int row) {
}
void DeviceView::Forget() {
boost::scoped_ptr<QMessageBox> dialog(new QMessageBox(
QMessageBox::Question, tr("Forget device"),
tr("Forgetting a device will remove it from this list and Clementine will have to rescan all the songs again next time you connect it."),
QMessageBox::Cancel, this));
QPushButton* forget =
dialog->addButton(tr("Forget device"), QMessageBox::DestructiveRole);
dialog->exec();
if (dialog->clickedButton() != forget)
return;
QModelIndex device_idx = MapToDevice(menu_index_);
if (manager_->GetLister(device_idx.row()) &&
manager_->GetLister(device_idx.row())->AskForScan()) {
boost::scoped_ptr<QMessageBox> dialog(new QMessageBox(
QMessageBox::Question, tr("Forget device"),
tr("Forgetting a device will remove it from this list and Clementine will have to rescan all the songs again next time you connect it."),
QMessageBox::Cancel, this));
QPushButton* forget =
dialog->addButton(tr("Forget device"), QMessageBox::DestructiveRole);
dialog->exec();
if (dialog->clickedButton() != forget)
return;
}
manager_->Forget(device_idx.row());
}

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.

View File

@ -1,11 +1,15 @@
#include "songresolver.h"
#include "config.h"
#include "core/logging.h"
#include "core/song.h"
#include "internet/internetmodel.h"
#include "internet/spotifyservice.h"
#include "libraryresolver.h"
#ifdef HAVE_SPOTIFY
#include "internet/spotifyservice.h"
#include "spotifyresolver.h"
#endif
SongResolver::SongResolver(LibraryBackendInterface* library, QObject* parent)
: QObject(parent),
@ -14,7 +18,9 @@ SongResolver::SongResolver(LibraryBackendInterface* library, QObject* parent)
resolved_(false) {
// Register in the order they should be checked.
RegisterResolver(new LibraryResolver(library));
#ifdef HAVE_SPOTIFY
RegisterResolver(new SpotifyResolver(InternetModel::Service<SpotifyService>()->server()));
#endif
}
SongResolver::~SongResolver() {