mirror of
https://github.com/clementine-player/Clementine
synced 2025-01-31 11:35:24 +01:00
MTP support for Mac... Currently crashes the entire USB bus so I wouldn't use it.
This commit is contained in:
parent
4235c0f49d
commit
75a576a5c2
@ -30,9 +30,13 @@ class MacDeviceLister : public DeviceLister {
|
||||
|
||||
struct MTPDevice {
|
||||
QString vendor;
|
||||
quint16 vendor_id;
|
||||
QString product;
|
||||
quint16 vendor_id;
|
||||
quint16 product_id;
|
||||
|
||||
int quirks;
|
||||
int bus;
|
||||
int address;
|
||||
};
|
||||
|
||||
public slots:
|
||||
@ -48,10 +52,13 @@ class MacDeviceLister : public DeviceLister {
|
||||
static void DiskUnmountCallback(
|
||||
DADiskRef disk, DADissenterRef dissenter, void* context);
|
||||
|
||||
void FoundMTPDevice(const MTPDevice& device, const QString& serial);
|
||||
|
||||
DASessionRef loop_session_;
|
||||
CFRunLoopRef run_loop_;
|
||||
|
||||
QMap<QString, QString> current_devices_;
|
||||
QMap<QString, MTPDevice> mtp_devices_;
|
||||
|
||||
static QSet<MTPDevice> sMTPDeviceList;
|
||||
};
|
||||
|
@ -81,6 +81,7 @@ void MacDeviceLister::Init() {
|
||||
d.vendor_id = device.vendor_id;
|
||||
d.product = QString::fromAscii(device.product);
|
||||
d.product_id = device.product_id;
|
||||
d.quirks = device.device_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,6 +228,11 @@ QString GetSerialForDevice(io_object_t device) {
|
||||
"USB/" + GetUSBRegistryEntryString(device, CFSTR(kUSBSerialNumberString)));
|
||||
}
|
||||
|
||||
QString GetSerialForMTPDevice(io_object_t device) {
|
||||
return QString(
|
||||
"MTP/" + GetUSBRegistryEntryString(device, CFSTR(kUSBSerialNumberString)));
|
||||
}
|
||||
|
||||
QString FindDeviceProperty(const QString& bsd_name, CFStringRef property) {
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
@ -340,6 +346,11 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
|
||||
io_object_t object;
|
||||
while ((object = IOIteratorNext(it))) {
|
||||
CFStringRef class_name = IOObjectCopyClass(object);
|
||||
BOOST_SCOPE_EXIT((class_name)(object)) {
|
||||
CFRelease(class_name);
|
||||
IOObjectRelease(object);
|
||||
} BOOST_SCOPE_EXIT_END
|
||||
|
||||
if (CFStringCompare(class_name, CFSTR(kIOUSBDeviceClassName), 0) == kCFCompareEqualTo) {
|
||||
NSString* vendor = (NSString*)GetPropertyForDevice(object, CFSTR(kUSBVendorString));
|
||||
NSString* product = (NSString*)GetPropertyForDevice(object, CFSTR(kUSBProductString));
|
||||
@ -351,6 +362,10 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
|
||||
device.product = QString::fromUtf8([product UTF8String]);
|
||||
device.vendor_id = [vendor_id unsignedShortValue];
|
||||
device.product_id = [product_id unsignedShortValue];
|
||||
device.quirks = 0;
|
||||
|
||||
device.bus = -1;
|
||||
device.address = -1;
|
||||
|
||||
if (device.vendor_id == 0x5ac) {
|
||||
// I think we can safely skip Apple products.
|
||||
@ -369,12 +384,17 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
|
||||
// Failed to get bus or address number.
|
||||
continue;
|
||||
}
|
||||
device.bus = bus;
|
||||
device.address = [addr intValue];
|
||||
|
||||
// First check the libmtp device list.
|
||||
if (sMTPDeviceList.contains(device)) {
|
||||
QSet<MTPDevice>::const_iterator it = sMTPDeviceList.find(device);
|
||||
if (it != sMTPDeviceList.end()) {
|
||||
qDebug() << "Matched device to libmtp list!";
|
||||
// emit.
|
||||
return;
|
||||
// Fill in quirks flags from libmtp.
|
||||
device.quirks = it->quirks;
|
||||
me->FoundMTPDevice(device, GetSerialForMTPDevice(object));
|
||||
continue;
|
||||
}
|
||||
|
||||
IOCFPlugInInterface** plugin_interface = NULL;
|
||||
@ -457,16 +477,31 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
|
||||
continue;
|
||||
}
|
||||
// Hurray! We made it!
|
||||
qDebug() << "New MTP device detected!";
|
||||
me->FoundMTPDevice(device, GetSerialForMTPDevice(object));
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(class_name);
|
||||
IOObjectRelease(object);
|
||||
}
|
||||
}
|
||||
|
||||
void MacDeviceLister::FoundMTPDevice(const MTPDevice& device, const QString& serial) {
|
||||
qDebug() << "New MTP device detected!";
|
||||
mtp_devices_[serial] = device;
|
||||
emit DeviceAdded(serial);
|
||||
}
|
||||
|
||||
bool IsMTPSerial(const QString& serial) {
|
||||
return serial.startsWith("MTP");
|
||||
}
|
||||
|
||||
QString MacDeviceLister::MakeFriendlyName(const QString& serial) {
|
||||
if (IsMTPSerial(serial)) {
|
||||
const MTPDevice& device = mtp_devices_[serial];
|
||||
if (device.vendor.isEmpty()) {
|
||||
return device.product;
|
||||
} else {
|
||||
return device.vendor + " " + device.product;
|
||||
}
|
||||
}
|
||||
QString bsd_name = current_devices_[serial];
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
@ -487,6 +522,19 @@ QString MacDeviceLister::MakeFriendlyName(const QString& serial) {
|
||||
}
|
||||
|
||||
QList<QUrl> MacDeviceLister::MakeDeviceUrls(const QString& serial) {
|
||||
if (IsMTPSerial(serial)) {
|
||||
const MTPDevice& device = mtp_devices_[serial];
|
||||
QString str;
|
||||
str.sprintf("gphoto2://usb-%d-%d/", device.bus, device.address);
|
||||
QUrl url(str);
|
||||
url.addQueryItem("vendor", device.vendor);
|
||||
url.addQueryItem("vendor_id", QString::number(device.vendor_id));
|
||||
url.addQueryItem("product", device.product);
|
||||
url.addQueryItem("product_id", QString::number(device.product_id));
|
||||
url.addQueryItem("quirks", QString::number(device.quirks));
|
||||
return QList<QUrl>() << url;
|
||||
}
|
||||
|
||||
QString bsd_name = current_devices_[serial];
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
@ -506,10 +554,13 @@ QList<QUrl> MacDeviceLister::MakeDeviceUrls(const QString& serial) {
|
||||
}
|
||||
|
||||
QStringList MacDeviceLister::DeviceUniqueIDs() {
|
||||
return current_devices_.keys();
|
||||
return current_devices_.keys() + mtp_devices_.keys();
|
||||
}
|
||||
|
||||
QVariantList MacDeviceLister::DeviceIcons(const QString& serial) {
|
||||
if (IsMTPSerial(serial)) {
|
||||
return QVariantList();
|
||||
}
|
||||
QString bsd_name = current_devices_[serial];
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
@ -538,14 +589,23 @@ QVariantList MacDeviceLister::DeviceIcons(const QString& serial) {
|
||||
}
|
||||
|
||||
QString MacDeviceLister::DeviceManufacturer(const QString& serial){
|
||||
if (IsMTPSerial(serial)) {
|
||||
return mtp_devices_[serial].vendor;
|
||||
}
|
||||
return FindDeviceProperty(current_devices_[serial], CFSTR(kUSBVendorString));
|
||||
}
|
||||
|
||||
QString MacDeviceLister::DeviceModel(const QString& serial){
|
||||
if (IsMTPSerial(serial)) {
|
||||
return mtp_devices_[serial].product;
|
||||
}
|
||||
return FindDeviceProperty(current_devices_[serial], CFSTR(kUSBProductString));
|
||||
}
|
||||
|
||||
quint64 MacDeviceLister::DeviceCapacity(const QString& serial){
|
||||
if (IsMTPSerial(serial)) {
|
||||
return 10000000;
|
||||
}
|
||||
QString bsd_name = current_devices_[serial];
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
@ -566,6 +626,9 @@ quint64 MacDeviceLister::DeviceCapacity(const QString& serial){
|
||||
}
|
||||
|
||||
quint64 MacDeviceLister::DeviceFreeSpace(const QString& serial){
|
||||
if (IsMTPSerial(serial)) {
|
||||
return 10000000;
|
||||
}
|
||||
QString bsd_name = current_devices_[serial];
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
@ -597,6 +660,8 @@ quint64 MacDeviceLister::DeviceFreeSpace(const QString& serial){
|
||||
QVariantMap MacDeviceLister::DeviceHardwareInfo(const QString& serial){return QVariantMap();}
|
||||
|
||||
void MacDeviceLister::UnmountDevice(const QString& serial) {
|
||||
if (IsMTPSerial(serial)) return;
|
||||
|
||||
QString bsd_name = current_devices_[serial];
|
||||
DADiskRef disk = DADiskCreateFromBSDName(
|
||||
kCFAllocatorDefault, loop_session_, bsd_name.toAscii().constData());
|
||||
|
@ -19,9 +19,10 @@
|
||||
#include <QRegExp>
|
||||
#include <QtDebug>
|
||||
|
||||
MtpConnection::MtpConnection(const QString& hostname)
|
||||
MtpConnection::MtpConnection(const QUrl& url)
|
||||
: device_(NULL)
|
||||
{
|
||||
QString hostname = url.host();
|
||||
// Parse the URL
|
||||
QRegExp host_re("^usb-(\\d+)-(\\d+)$");
|
||||
|
||||
@ -33,6 +34,23 @@ MtpConnection::MtpConnection(const QString& hostname)
|
||||
const unsigned int bus_location = host_re.cap(1).toInt();
|
||||
const unsigned int device_num = host_re.cap(2).toInt();
|
||||
|
||||
if (url.hasQueryItem("vendor")) {
|
||||
LIBMTP_raw_device_t* raw_device = (LIBMTP_raw_device_t*)malloc(sizeof(LIBMTP_raw_device_t));
|
||||
raw_device->device_entry.vendor = url.queryItemValue("vendor").toAscii().data();
|
||||
raw_device->device_entry.product = url.queryItemValue("product").toAscii().data();
|
||||
raw_device->device_entry.vendor_id = url.queryItemValue("vendor_id").toUShort();
|
||||
raw_device->device_entry.product_id = url.queryItemValue("product_id").toUShort();
|
||||
raw_device->device_entry.device_flags = url.queryItemValue("quirks").toUInt();
|
||||
|
||||
raw_device->bus_location = bus_location;
|
||||
raw_device->devnum = device_num;
|
||||
|
||||
qDebug() << "\\o/" << url;
|
||||
|
||||
device_ = LIBMTP_Open_Raw_Device(raw_device);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a list of devices from libmtp and figure out which one is ours
|
||||
int count = 0;
|
||||
LIBMTP_raw_device_t* raw_devices = NULL;
|
||||
|
@ -17,13 +17,13 @@
|
||||
#ifndef MTPCONNECTION_H
|
||||
#define MTPCONNECTION_H
|
||||
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include <libmtp.h>
|
||||
|
||||
class MtpConnection {
|
||||
public:
|
||||
MtpConnection(const QString& hostname);
|
||||
MtpConnection(const QUrl& url);
|
||||
~MtpConnection();
|
||||
|
||||
bool is_valid() const { return device_; }
|
||||
|
@ -47,7 +47,7 @@ void MtpDevice::Init() {
|
||||
InitBackendDirectory("/", first_time_, false);
|
||||
model_->Init();
|
||||
|
||||
loader_ = new MtpLoader(url_.host(), manager_->task_manager(), backend_,
|
||||
loader_ = new MtpLoader(url_, manager_->task_manager(), backend_,
|
||||
shared_from_this());
|
||||
loader_->moveToThread(loader_thread_);
|
||||
|
||||
|
@ -23,11 +23,11 @@
|
||||
|
||||
#include <libmtp.h>
|
||||
|
||||
MtpLoader::MtpLoader(const QString& hostname, TaskManager* task_manager,
|
||||
MtpLoader::MtpLoader(const QUrl& url, TaskManager* task_manager,
|
||||
LibraryBackend* backend, boost::shared_ptr<ConnectedDevice> device)
|
||||
: QObject(NULL),
|
||||
device_(device),
|
||||
hostname_(hostname),
|
||||
url_(url),
|
||||
task_manager_(task_manager),
|
||||
backend_(backend)
|
||||
{
|
||||
@ -50,7 +50,7 @@ void MtpLoader::LoadDatabase() {
|
||||
}
|
||||
|
||||
bool MtpLoader::TryLoad() {
|
||||
MtpConnection dev(hostname_);
|
||||
MtpConnection dev(url_);
|
||||
if (!dev.is_valid()) {
|
||||
emit Error(tr("Error connecting MTP device"));
|
||||
return false;
|
||||
@ -65,7 +65,7 @@ bool MtpLoader::TryLoad() {
|
||||
Song song;
|
||||
song.InitFromMTP(track);
|
||||
song.set_directory_id(1);
|
||||
song.set_filename("mtp://" + hostname_ + "/" + song.filename());
|
||||
song.set_filename("mtp://" + url_.host() + "/" + song.filename());
|
||||
songs << song;
|
||||
|
||||
tracks = tracks->next;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#define MTPLOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
@ -29,7 +30,7 @@ class MtpLoader : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MtpLoader(const QString& hostname, TaskManager* task_manager,
|
||||
MtpLoader(const QUrl& url, TaskManager* task_manager,
|
||||
LibraryBackend* backend, boost::shared_ptr<ConnectedDevice> device);
|
||||
~MtpLoader();
|
||||
|
||||
@ -48,7 +49,7 @@ private:
|
||||
boost::shared_ptr<ConnectedDevice> device_;
|
||||
QThread* original_thread_;
|
||||
|
||||
QString hostname_;
|
||||
QUrl url_;
|
||||
TaskManager* task_manager_;
|
||||
LibraryBackend* backend_;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user