Allow GetSupportedFiletypes to return an error, and make it possible to request a list of supported filetypes at the same time as opening the device for copying - making things much faster on MTP devices.
This commit is contained in:
parent
d7e71ad14a
commit
e4f5e97b17
@ -62,9 +62,9 @@ public:
|
||||
|
||||
virtual TranscodeMode GetTranscodeMode() const { return Transcode_Never; }
|
||||
virtual Song::FileType GetTranscodeFormat() const { return Song::Type_Unknown; }
|
||||
virtual QList<Song::FileType> SupportedFiletypes() { return QList<Song::FileType>(); }
|
||||
virtual bool GetSupportedFiletypes(QList<Song::FileType>* ret) { return true; }
|
||||
|
||||
virtual void StartCopy() {}
|
||||
virtual bool StartCopy(QList<Song::FileType>* supported_types) { return true;}
|
||||
virtual bool CopyToStorage(const CopyJob& job) = 0;
|
||||
virtual void FinishCopy(bool success) {}
|
||||
|
||||
|
@ -72,9 +72,13 @@ void Organise::Start() {
|
||||
void Organise::ProcessSomeFiles() {
|
||||
if (!started_) {
|
||||
transcode_temp_name_.open();
|
||||
supported_filetypes_ = destination_->SupportedFiletypes();
|
||||
|
||||
destination_->StartCopy();
|
||||
if (!destination_->StartCopy(&supported_filetypes_)) {
|
||||
// Failed to start - mark everything as failed :(
|
||||
foreach (const Task& task, tasks_pending_)
|
||||
files_with_errors_ << task.filename_;
|
||||
tasks_pending_.clear();
|
||||
}
|
||||
started_ = true;
|
||||
}
|
||||
|
||||
|
@ -75,9 +75,11 @@ void AfcDevice::CopyFinished(bool success) {
|
||||
QMetaObject::invokeMethod(loader_, "LoadDatabase");
|
||||
}
|
||||
|
||||
void AfcDevice::StartCopy() {
|
||||
GPodDevice::StartCopy();
|
||||
bool AfcDevice::StartCopy(QList<Song::FileType>* supported_types) {
|
||||
GPodDevice::StartCopy(supported_types);
|
||||
connection_.reset(new iMobileDeviceConnection(url_.host()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AfcDevice::CopyToStorage(const CopyJob& job) {
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
|
||||
static QStringList url_schemes() { return QStringList() << "afc"; }
|
||||
|
||||
void StartCopy();
|
||||
bool StartCopy(QList<Song::FileType>* supported_types);
|
||||
bool CopyToStorage(const CopyJob& job);
|
||||
void FinishCopy(bool success);
|
||||
|
||||
|
@ -174,12 +174,6 @@ void DeviceProperties::UpdateHardwareInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
typedef QList<Song::FileType> TypeList;
|
||||
typedef QFuture<TypeList> DeviceTypesFuture;
|
||||
typedef QFutureWatcher<TypeList> DeviceTypesFutureWatcher;
|
||||
}
|
||||
|
||||
void DeviceProperties::UpdateFormats() {
|
||||
QString id = index_.data(DeviceManager::Role_UniqueId).toString();
|
||||
DeviceLister* lister = manager_->GetLister(index_.row());
|
||||
@ -222,9 +216,11 @@ void DeviceProperties::UpdateFormats() {
|
||||
if (!updating_formats_) {
|
||||
// Get the device's supported formats list. This takes a long time and it
|
||||
// blocks, so do it in the background.
|
||||
DeviceTypesFuture future = QtConcurrent::run(
|
||||
boost::bind(&ConnectedDevice::SupportedFiletypes, device));
|
||||
DeviceTypesFutureWatcher* watcher = new DeviceTypesFutureWatcher(this);
|
||||
supported_formats_.clear();
|
||||
|
||||
QFuture<bool> future = QtConcurrent::run(boost::bind(
|
||||
&ConnectedDevice::GetSupportedFiletypes, device, &supported_formats_));
|
||||
QFutureWatcher<bool>* watcher = new QFutureWatcher<bool>(this);
|
||||
watcher->setFuture(future);
|
||||
|
||||
connect(watcher, SIGNAL(finished()), SLOT(UpdateFormatsFinished()));
|
||||
@ -260,23 +256,25 @@ void DeviceProperties::OpenDevice() {
|
||||
}
|
||||
|
||||
void DeviceProperties::UpdateFormatsFinished() {
|
||||
DeviceTypesFutureWatcher* watcher = static_cast<DeviceTypesFutureWatcher*>(sender());
|
||||
QFutureWatcher<bool>* watcher = static_cast<QFutureWatcher<bool>*>(sender());
|
||||
watcher->deleteLater();
|
||||
updating_formats_ = false;
|
||||
|
||||
TypeList list = watcher->future().result();
|
||||
if (!watcher->future().result()) {
|
||||
supported_formats_.clear();
|
||||
}
|
||||
|
||||
// Hide widgets if there are no supported types
|
||||
ui_->supported_formats_container->setVisible(!list.isEmpty());
|
||||
ui_->transcode_unsupported->setEnabled(!list.isEmpty());
|
||||
ui_->supported_formats_container->setVisible(!supported_formats_.isEmpty());
|
||||
ui_->transcode_unsupported->setEnabled(!supported_formats_.isEmpty());
|
||||
|
||||
if (ui_->transcode_unsupported->isChecked() && list.isEmpty()) {
|
||||
if (ui_->transcode_unsupported->isChecked() && supported_formats_.isEmpty()) {
|
||||
ui_->transcode_off->setChecked(true);
|
||||
}
|
||||
|
||||
// Populate supported types list
|
||||
ui_->supported_formats->clear();
|
||||
foreach (Song::FileType type, list) {
|
||||
foreach (Song::FileType type, supported_formats_) {
|
||||
QListWidgetItem* item = new QListWidgetItem(Song::TextForFiletype(type));
|
||||
ui_->supported_formats->addItem(item);
|
||||
}
|
||||
@ -288,7 +286,7 @@ void DeviceProperties::UpdateFormatsFinished() {
|
||||
if (preset.type_ == Song::Type_Unknown) {
|
||||
// The user hasn't chosen a format for this device yet, so work our way down
|
||||
// a list of some preferred formats, picking the first one that is supported
|
||||
preset = Transcoder::PresetForFileType(Transcoder::PickBestFormat(list));
|
||||
preset = Transcoder::PresetForFileType(Transcoder::PickBestFormat(supported_formats_));
|
||||
}
|
||||
ui_->transcode_format->setCurrentIndex(ui_->transcode_format->findText(preset.name_));
|
||||
|
||||
|
@ -55,6 +55,7 @@ private:
|
||||
QPersistentModelIndex index_;
|
||||
|
||||
bool updating_formats_;
|
||||
QList<Song::FileType> supported_formats_;
|
||||
};
|
||||
|
||||
#endif // DEVICEPROPERTIES_H
|
||||
|
@ -63,7 +63,7 @@ void GPodDevice::LoadFinished(Itdb_iTunesDB* db) {
|
||||
loader_ = NULL;
|
||||
}
|
||||
|
||||
void GPodDevice::StartCopy() {
|
||||
bool GPodDevice::StartCopy(QList<Song::FileType>* supported_filetypes) {
|
||||
{
|
||||
// Wait for the database to be loaded
|
||||
QMutexLocker l(&db_mutex_);
|
||||
@ -73,6 +73,10 @@ void GPodDevice::StartCopy() {
|
||||
|
||||
// Ensure only one "organise files" can be active at any one time
|
||||
db_busy_.lock();
|
||||
|
||||
if (supported_filetypes)
|
||||
GetSupportedFiletypes(supported_filetypes);
|
||||
return true;
|
||||
}
|
||||
|
||||
Itdb_Track* GPodDevice::AddTrackToITunesDb(const Song& metadata) {
|
||||
@ -157,7 +161,7 @@ void GPodDevice::FinishCopy(bool success) {
|
||||
}
|
||||
|
||||
void GPodDevice::StartDelete() {
|
||||
StartCopy();
|
||||
StartCopy(NULL);
|
||||
}
|
||||
|
||||
bool GPodDevice::RemoveTrackFromITunesDb(const QString& path, const QString& relative_to) {
|
||||
@ -220,9 +224,8 @@ void GPodDevice::FinishDelete(bool success) {
|
||||
ConnectedDevice::FinishDelete(success);
|
||||
}
|
||||
|
||||
QList<Song::FileType> GPodDevice::SupportedFiletypes() {
|
||||
QList<Song::FileType> ret;
|
||||
ret << Song::Type_Mp4;
|
||||
ret << Song::Type_Mpeg;
|
||||
return ret;
|
||||
bool GPodDevice::GetSupportedFiletypes(QList<Song::FileType>* ret) {
|
||||
*ret << Song::Type_Mp4;
|
||||
*ret << Song::Type_Mpeg;
|
||||
return true;
|
||||
}
|
||||
|
@ -41,9 +41,9 @@ public:
|
||||
|
||||
static QStringList url_schemes() { return QStringList() << "ipod"; }
|
||||
|
||||
QList<Song::FileType> SupportedFiletypes();
|
||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
||||
|
||||
void StartCopy();
|
||||
bool StartCopy(QList<Song::FileType>* supported_types);
|
||||
bool CopyToStorage(const CopyJob& job);
|
||||
void FinishCopy(bool success);
|
||||
|
||||
|
@ -66,12 +66,22 @@ void MtpDevice::LoadFinished() {
|
||||
db_busy_.unlock();
|
||||
}
|
||||
|
||||
void MtpDevice::StartCopy() {
|
||||
bool MtpDevice::StartCopy(QList<Song::FileType>* supported_types) {
|
||||
// Ensure only one "organise files" can be active at any one time
|
||||
db_busy_.lock();
|
||||
|
||||
// Connect to the device
|
||||
connection_.reset(new MtpConnection(url_.host()));
|
||||
|
||||
// Did the caller want a list of supported types?
|
||||
if (supported_types) {
|
||||
if (!GetSupportedFiletypes(supported_types, connection_->device())) {
|
||||
FinishCopy(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ProgressCallback(uint64_t const sent, uint64_t const total,
|
||||
@ -131,7 +141,7 @@ void MtpDevice::FinishCopy(bool success) {
|
||||
}
|
||||
|
||||
void MtpDevice::StartDelete() {
|
||||
StartCopy();
|
||||
StartCopy(NULL);
|
||||
}
|
||||
|
||||
bool MtpDevice::DeleteFromStorage(const DeleteJob& job) {
|
||||
@ -160,40 +170,42 @@ void MtpDevice::FinishDelete(bool success) {
|
||||
FinishCopy(success);
|
||||
}
|
||||
|
||||
QList<Song::FileType> MtpDevice::SupportedFiletypes() {
|
||||
QList<Song::FileType> ret;
|
||||
|
||||
uint16_t* list = NULL;
|
||||
uint16_t length = 0;
|
||||
|
||||
bool MtpDevice::GetSupportedFiletypes(QList<Song::FileType>* ret) {
|
||||
QMutexLocker l(&db_busy_);
|
||||
MtpConnection connection(url_.host());
|
||||
if (!connection.is_valid()) {
|
||||
qWarning() << "Error connecting to MTP device, couldn't get list of supported filetypes";
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LIBMTP_Get_Supported_Filetypes(connection.device(), &list, &length)
|
||||
return GetSupportedFiletypes(ret, connection.device());
|
||||
}
|
||||
|
||||
bool MtpDevice::GetSupportedFiletypes(QList<Song::FileType>* ret, LIBMTP_mtpdevice_t* device) {
|
||||
uint16_t* list = NULL;
|
||||
uint16_t length = 0;
|
||||
|
||||
if (LIBMTP_Get_Supported_Filetypes(device, &list, &length)
|
||||
|| !list || !length)
|
||||
return ret;
|
||||
return false;
|
||||
|
||||
for (int i=0 ; i<length ; ++i) {
|
||||
switch (LIBMTP_filetype_t(list[i])) {
|
||||
case LIBMTP_FILETYPE_WAV: ret << Song::Type_Wav; break;
|
||||
case LIBMTP_FILETYPE_WAV: *ret << Song::Type_Wav; break;
|
||||
case LIBMTP_FILETYPE_MP2:
|
||||
case LIBMTP_FILETYPE_MP3: ret << Song::Type_Mpeg; break;
|
||||
case LIBMTP_FILETYPE_WMA: ret << Song::Type_Asf; break;
|
||||
case LIBMTP_FILETYPE_MP3: *ret << Song::Type_Mpeg; break;
|
||||
case LIBMTP_FILETYPE_WMA: *ret << Song::Type_Asf; break;
|
||||
case LIBMTP_FILETYPE_MP4:
|
||||
case LIBMTP_FILETYPE_M4A:
|
||||
case LIBMTP_FILETYPE_AAC: ret << Song::Type_Mp4; break;
|
||||
case LIBMTP_FILETYPE_AAC: *ret << Song::Type_Mp4; break;
|
||||
case LIBMTP_FILETYPE_FLAC:
|
||||
ret << Song::Type_Flac;
|
||||
ret << Song::Type_OggFlac;
|
||||
*ret << Song::Type_Flac;
|
||||
*ret << Song::Type_OggFlac;
|
||||
break;
|
||||
case LIBMTP_FILETYPE_OGG:
|
||||
ret << Song::Type_OggVorbis;
|
||||
ret << Song::Type_OggSpeex;
|
||||
ret << Song::Type_OggFlac;
|
||||
*ret << Song::Type_OggVorbis;
|
||||
*ret << Song::Type_OggSpeex;
|
||||
*ret << Song::Type_OggFlac;
|
||||
break;
|
||||
default:
|
||||
qDebug() << "Unknown MTP file format" <<
|
||||
@ -203,5 +215,5 @@ QList<Song::FileType> MtpDevice::SupportedFiletypes() {
|
||||
}
|
||||
|
||||
free(list);
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ public:
|
||||
|
||||
void Init();
|
||||
|
||||
QList<Song::FileType> SupportedFiletypes();
|
||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
||||
|
||||
void StartCopy();
|
||||
bool StartCopy(QList<Song::FileType>* supported_types);
|
||||
bool CopyToStorage(const CopyJob& job);
|
||||
void FinishCopy(bool success);
|
||||
|
||||
@ -53,6 +53,9 @@ public:
|
||||
private slots:
|
||||
void LoadFinished();
|
||||
|
||||
private:
|
||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret, LIBMTP_mtpdevice_t* device);
|
||||
|
||||
private:
|
||||
static bool sInitialisedLibMTP;
|
||||
|
||||
|
@ -62,7 +62,7 @@ void WmdmDevice::LoadFinished() {
|
||||
loader_ = NULL;
|
||||
}
|
||||
|
||||
void WmdmDevice::StartCopy() {
|
||||
bool WmdmDevice::StartCopy(QList<Song::FileType>* supported_types) {
|
||||
// Ensure only one "organise files" can be active at any one time
|
||||
db_busy_.lock();
|
||||
|
||||
@ -82,6 +82,19 @@ void WmdmDevice::StartCopy() {
|
||||
destination->QueryInterface(IID_IWMDMStorage3, (void**)&storage_);
|
||||
|
||||
destination->Release();
|
||||
|
||||
// Did the caller want a list of supported filetypes?
|
||||
if (supported_types) {
|
||||
IWMDMDevice* device = thread_->GetDeviceByCanonicalName(canonical_name);
|
||||
if (!GetSupportedFiletypes(supported_types, device)) {
|
||||
device->Release();
|
||||
FinishCopy(false);
|
||||
return false;
|
||||
}
|
||||
device->Release();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WmdmDevice::CopyToStorage(const CopyJob& job) {
|
||||
@ -213,15 +226,7 @@ void WmdmDevice::FinishDelete(bool success) {
|
||||
FinishCopy(success);
|
||||
}
|
||||
|
||||
QList<Song::FileType> WmdmDevice::SupportedFiletypes() {
|
||||
QList<Song::FileType> ret;
|
||||
WmdmThread thread;
|
||||
|
||||
// Get the device
|
||||
WmdmLister* wmdm_lister = static_cast<WmdmLister*>(lister());
|
||||
QString canonical_name = wmdm_lister->DeviceCanonicalName(unique_id());
|
||||
IWMDMDevice* device = thread.GetDeviceByCanonicalName(canonical_name);
|
||||
|
||||
bool WmdmDevice::GetSupportedFiletypes(QList<Song::FileType>* ret, IWMDMDevice* device) {
|
||||
// Get a list of supported formats
|
||||
uint32_t format_count = 0;
|
||||
uint32_t mime_count = 0;
|
||||
@ -231,28 +236,40 @@ QList<Song::FileType> WmdmDevice::SupportedFiletypes() {
|
||||
if (device->GetFormatSupport(
|
||||
&formats, &format_count, &mime_types, &mime_count)) {
|
||||
qWarning() << "Unable to get a list of supported formats for device" << canonical_name;
|
||||
device->Release();
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
device->Release();
|
||||
|
||||
// Find known mime types
|
||||
for (int i=0 ; i<mime_count ; ++i) {
|
||||
QString type = QString::fromWCharArray(mime_types[i]);
|
||||
if (type == "audio/mp3" || type == "audio/mpeg")
|
||||
ret << Song::Type_Mpeg;
|
||||
*ret << Song::Type_Mpeg;
|
||||
else if (type == "audio/x-ms-wma")
|
||||
ret << Song::Type_Asf;
|
||||
*ret << Song::Type_Asf;
|
||||
else if (type == "audio/wav")
|
||||
ret << Song::Type_Wav;
|
||||
*ret << Song::Type_Wav;
|
||||
else if (type == "audio/mp4")
|
||||
ret << Song::Type_Mp4;
|
||||
*ret << Song::Type_Mp4;
|
||||
else if (type == "audio/ogg" || type == "audio/vorbis")
|
||||
ret << Song::Type_OggVorbis;
|
||||
*ret << Song::Type_OggVorbis;
|
||||
}
|
||||
|
||||
CoTaskMemFree(formats);
|
||||
CoTaskMemFree(mime_types);
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WmdmDevice::GetSupportedFiletypes(QList<Song::FileType>* ret) {
|
||||
WmdmThread thread;
|
||||
|
||||
// Get the device
|
||||
WmdmLister* wmdm_lister = static_cast<WmdmLister*>(lister());
|
||||
QString canonical_name = wmdm_lister->DeviceCanonicalName(unique_id());
|
||||
IWMDMDevice* device = thread.GetDeviceByCanonicalName(canonical_name);
|
||||
|
||||
bool success = GetSupportedFiletypes(ret, device);
|
||||
device->Release();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
class WmdmLoader;
|
||||
class WmdmThread;
|
||||
|
||||
struct IWMDMDevice;
|
||||
struct IWMDMStorage3;
|
||||
struct IWMDMStorageControl3;
|
||||
|
||||
@ -40,9 +41,9 @@ public:
|
||||
|
||||
void Init();
|
||||
|
||||
QList<Song::FileType> SupportedFiletypes();
|
||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret);
|
||||
|
||||
void StartCopy();
|
||||
bool StartCopy(QList<Song::FileType>* supported_types);
|
||||
bool CopyToStorage(const CopyJob& job);
|
||||
void FinishCopy(bool success);
|
||||
|
||||
@ -53,6 +54,9 @@ public:
|
||||
private slots:
|
||||
void LoadFinished();
|
||||
|
||||
private:
|
||||
bool GetSupportedFiletypes(QList<Song::FileType>* ret, IWMDMDevice* device);
|
||||
|
||||
private:
|
||||
QThread* loader_thread_;
|
||||
WmdmLoader* loader_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user