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:
David Sansome 2010-08-30 12:22:15 +00:00
parent d7e71ad14a
commit e4f5e97b17
12 changed files with 120 additions and 76 deletions

View File

@ -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) {}

View File

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

View File

@ -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) {

View File

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

View File

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

View File

@ -55,6 +55,7 @@ private:
QPersistentModelIndex index_;
bool updating_formats_;
QList<Song::FileType> supported_formats_;
};
#endif // DEVICEPROPERTIES_H

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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