| /* This file is part of the KDE project |
| Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org> |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) version 3, or any |
| later version accepted by the membership of KDE e.V. (or its |
| successor approved by the membership of KDE e.V.), Nokia Corporation |
| (or its successors, if any) and the KDE Free Qt Foundation, which shall |
| act as a proxy defined in Section 6 of version 3 of the license. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with this library. If not, see <http://www.gnu.org/licenses/>. |
| |
| */ |
| |
| #include "globalconfig.h" |
| #include "globalconfig_p.h" |
| |
| #include "factory_p.h" |
| #include "objectdescription.h" |
| #include "phonondefs_p.h" |
| #include "platformplugin.h" |
| #include "backendinterface.h" |
| #include "qsettingsgroup_p.h" |
| #include "phononnamespace_p.h" |
| #include "pulsesupport.h" |
| |
| #include <QtCore/QList> |
| #include <QtCore/QVariant> |
| |
| QT_BEGIN_NAMESPACE |
| |
| namespace Phonon |
| { |
| |
| GlobalConfigPrivate::GlobalConfigPrivate() : config(QLatin1String("kde.org"), QLatin1String("libphonon")) |
| { |
| } |
| |
| GlobalConfig::GlobalConfig() |
| : k_ptr(new GlobalConfigPrivate) |
| { |
| } |
| |
| GlobalConfig::~GlobalConfig() |
| { |
| delete k_ptr; |
| } |
| |
| enum WhatToFilter { |
| FilterAdvancedDevices = 1, |
| FilterHardwareDevices = 2, |
| FilterUnavailableDevices = 4 |
| }; |
| |
| static void filter(ObjectDescriptionType type, BackendInterface *backendIface, QList<int> *list, int whatToFilter) |
| { |
| QMutableListIterator<int> it(*list); |
| while (it.hasNext()) { |
| QHash<QByteArray, QVariant> properties; |
| if (backendIface) |
| properties = backendIface->objectDescriptionProperties(type, it.next()); |
| else |
| properties = PulseSupport::getInstance()->objectDescriptionProperties(type, it.next()); |
| QVariant var; |
| if (whatToFilter & FilterAdvancedDevices) { |
| var = properties.value("isAdvanced"); |
| if (var.isValid() && var.toBool()) { |
| it.remove(); |
| continue; |
| } |
| } |
| if (whatToFilter & FilterHardwareDevices) { |
| var = properties.value("isHardwareDevice"); |
| if (var.isValid() && var.toBool()) { |
| it.remove(); |
| continue; |
| #ifndef QT_NO_PHONON_SETTINGSGROUP |
| } |
| } |
| if (whatToFilter & FilterUnavailableDevices) { |
| var = properties.value("available"); |
| if (var.isValid() && !var.toBool()) { |
| it.remove(); |
| continue; |
| } |
| } |
| } |
| } |
| |
| static QList<int> sortDevicesByCategoryPriority(const GlobalConfig *config, const QSettingsGroup *backendConfig, ObjectDescriptionType type, Phonon::Category category, QList<int> &defaultList) |
| { |
| Q_ASSERT(config); Q_UNUSED(config); |
| Q_ASSERT(backendConfig); |
| Q_ASSERT(type == AudioOutputDeviceType || type == AudioCaptureDeviceType); |
| |
| if (defaultList.size() <= 1) { |
| // nothing to sort |
| return defaultList; |
| } else { |
| // make entries unique |
| QSet<int> seen; |
| QMutableListIterator<int> it(defaultList); |
| while (it.hasNext()) { |
| if (seen.contains(it.next())) { |
| it.remove(); |
| } else { |
| seen.insert(it.value()); |
| } |
| } |
| } |
| |
| QList<int> deviceList; |
| PulseSupport *pulse = PulseSupport::getInstance(); |
| if (pulse->isActive()) { |
| deviceList = pulse->objectIndexesByCategory(type, category); |
| } else { |
| QString categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(category)); |
| if (!backendConfig->hasKey(categoryKey)) { |
| // no list in config for the given category |
| categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(Phonon::NoCategory)); |
| if (!backendConfig->hasKey(categoryKey)) { |
| // no list in config for NoCategory |
| return defaultList; |
| } |
| } |
| |
| //Now the list from d->config |
| deviceList = backendConfig->value(categoryKey, QList<int>()); |
| } |
| |
| //if there are devices in d->config that the backend doesn't report, remove them from the list |
| QMutableListIterator<int> i(deviceList); |
| while (i.hasNext()) { |
| if (0 == defaultList.removeAll(i.next())) { |
| i.remove(); |
| } |
| } |
| |
| //if the backend reports more devices that are not in d->config append them to the list |
| deviceList += defaultList; |
| |
| return deviceList; |
| } |
| |
| bool GlobalConfig::hideAdvancedDevices() const |
| { |
| K_D(const GlobalConfig); |
| //The devices need to be stored independently for every backend |
| const QSettingsGroup generalGroup(&d->config, QLatin1String("General")); |
| return generalGroup.value(QLatin1String("HideAdvancedDevices"), true); |
| } |
| |
| void GlobalConfig::setHideAdvancedDevices(bool hide) |
| { |
| K_D(GlobalConfig); |
| QSettingsGroup generalGroup(&d->config, QLatin1String("General")); |
| generalGroup.setValue(QLatin1String("HideAdvancedDevices"), hide); |
| } |
| |
| static bool isHiddenAudioOutputDevice(const GlobalConfig *config, int i) |
| { |
| Q_ASSERT(config); |
| |
| if (!config->hideAdvancedDevices()) |
| return false; |
| |
| AudioOutputDevice ad = AudioOutputDevice::fromIndex(i); |
| const QVariant var = ad.property("isAdvanced"); |
| return (var.isValid() && var.toBool()); |
| } |
| |
| #ifndef QT_NO_PHONON_AUDIOCAPTURE |
| static bool isHiddenAudioCaptureDevice(const GlobalConfig *config, int i) |
| { |
| Q_ASSERT(config); |
| |
| if (!config->hideAdvancedDevices()) |
| return false; |
| |
| AudioCaptureDevice ad = AudioCaptureDevice::fromIndex(i); |
| const QVariant var = ad.property("isAdvanced"); |
| return (var.isValid() && var.toBool()); |
| } |
| #endif |
| |
| static QList<int> reindexList(const GlobalConfig *config, Phonon::Category category, QList<int>newOrder, bool output) |
| { |
| Q_ASSERT(config); |
| #ifdef QT_NO_PHONON_AUDIOCAPTURE |
| Q_ASSERT(output); |
| #endif |
| |
| /*QString sb; |
| sb = QString("(Size %1)").arg(currentList.size()); |
| foreach (int i, currentList) |
| sb += QString("%1, ").arg(i); |
| fprintf(stderr, "=== Reindex Current: %s\n", sb.toUtf8().constData()); |
| sb = QString("(Size %1)").arg(newOrder.size()); |
| foreach (int i, newOrder) |
| sb += QString("%1, ").arg(i); |
| fprintf(stderr, "=== Reindex Before : %s\n", sb.toUtf8().constData());*/ |
| |
| QList<int> currentList; |
| if (output) |
| currentList = config->audioOutputDeviceListFor(category, GlobalConfig::ShowUnavailableDevices|GlobalConfig::ShowAdvancedDevices); |
| #ifndef QT_NO_PHONON_AUDIOCAPTURE |
| else |
| currentList = config->audioCaptureDeviceListFor(category, GlobalConfig::ShowUnavailableDevices|GlobalConfig::ShowAdvancedDevices); |
| #endif |
| |
| QList<int> newList; |
| |
| foreach (int i, newOrder) { |
| int found = currentList.indexOf(i); |
| if (found < 0) { |
| // It's not in the list, so something is odd (e.g. client error). Ignore it. |
| continue; |
| } |
| |
| // Iterate through the list from this point onward. If there are hidden devices |
| // immediately following, take them too. |
| newList.append(currentList.takeAt(found)); |
| while (found < currentList.size()) { |
| bool hidden = true; |
| if (output) |
| hidden = isHiddenAudioOutputDevice(config, currentList.at(found)); |
| #ifndef QT_NO_PHONON_AUDIOCAPTURE |
| else |
| hidden = isHiddenAudioCaptureDevice(config, currentList.at(found)); |
| #endif |
| |
| if (!hidden) |
| break; |
| newList.append(currentList.takeAt(found)); |
| } |
| } |
| |
| // If there are any devices left in.. just tack them on the end. |
| if (currentList.size() > 0) |
| newList += currentList; |
| |
| /*sb = QString("(Size %1)").arg(newList.size()); |
| foreach (int i, newList) |
| sb += QString("%1, ").arg(i); |
| fprintf(stderr, "=== Reindex After : %s\n", sb.toUtf8().constData());*/ |
| return newList; |
| } |
| |
| |
| void GlobalConfig::setAudioOutputDeviceListFor(Phonon::Category category, QList<int> order) |
| { |
| PulseSupport *pulse = PulseSupport::getInstance(); |
| if (pulse->isActive()) { |
| pulse->setOutputDevicePriorityForCategory(category, order); |
| return; |
| } |
| |
| K_D(GlobalConfig); |
| QSettingsGroup backendConfig(&d->config, QLatin1String("AudioOutputDevice")); // + Factory::identifier()); |
| |
| order = reindexList(this, category, order, true); |
| |
| const QList<int> noCategoryOrder = audioOutputDeviceListFor(Phonon::NoCategory, ShowUnavailableDevices|ShowAdvancedDevices); |
| if (category != Phonon::NoCategory && order == noCategoryOrder) { |
| backendConfig.removeEntry(QLatin1String("Category_") + QString::number(category)); |
| } else { |
| backendConfig.setValue(QLatin1String("Category_") + QString::number(category), order); |
| } |
| } |
| #endif //QT_NO_PHONON_SETTINGSGROUP |
| |
| #ifndef QT_NO_PHONON_SETTINGSGROUP |
| QList<int> GlobalConfig::audioOutputDeviceListFor(Phonon::Category category, int override) const |
| { |
| K_D(const GlobalConfig); |
| |
| const bool hide = ((override & AdvancedDevicesFromSettings) |
| ? hideAdvancedDevices() |
| : static_cast<bool>(override & HideAdvancedDevices)); |
| |
| QList<int> defaultList; |
| |
| PulseSupport *pulse = PulseSupport::getInstance(); |
| if (pulse->isActive()) { |
| defaultList = pulse->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); |
| if (hide || (override & HideUnavailableDevices)) { |
| filter(AudioOutputDeviceType, NULL, &defaultList, |
| (hide ? FilterAdvancedDevices : 0) |
| | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) |
| ); |
| } |
| } else { |
| BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend()); |
| |
| #ifndef QT_NO_PHONON_PLATFORMPLUGIN |
| if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) { |
| // the platform plugin lists the audio devices for the platform |
| // this list already is in default order (as defined by the platform plugin) |
| defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); |
| if (hide) { |
| QMutableListIterator<int> it(defaultList); |
| while (it.hasNext()) { |
| AudioOutputDevice objDesc = AudioOutputDevice::fromIndex(it.next()); |
| const QVariant var = objDesc.property("isAdvanced"); |
| if (var.isValid() && var.toBool()) { |
| it.remove(); |
| } |
| } |
| } |
| } |
| #endif //QT_NO_PHONON_PLATFORMPLUGIN |
| |
| // lookup the available devices directly from the backend |
| if (backendIface) { |
| // this list already is in default order (as defined by the backend) |
| QList<int> list = backendIface->objectDescriptionIndexes(Phonon::AudioOutputDeviceType); |
| if (hide || !defaultList.isEmpty() || (override & HideUnavailableDevices)) { |
| filter(AudioOutputDeviceType, backendIface, &list, |
| (hide ? FilterAdvancedDevices : 0) |
| // the platform plugin maybe already provided the hardware devices? |
| | (defaultList.isEmpty() ? 0 : FilterHardwareDevices) |
| | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) |
| ); |
| } |
| defaultList += list; |
| } |
| } |
| |
| const QSettingsGroup backendConfig(&d->config, QLatin1String("AudioOutputDevice")); // + Factory::identifier()); |
| return sortDevicesByCategoryPriority(this, &backendConfig, AudioOutputDeviceType, category, defaultList); |
| } |
| #endif //QT_NO_PHONON_SETTINGSGROUP |
| int GlobalConfig::audioOutputDeviceFor(Phonon::Category category, int override) const |
| { |
| #ifndef QT_NO_PHONON_SETTINGSGROUP |
| QList<int> ret = audioOutputDeviceListFor(category, override); |
| if (!ret.isEmpty()) |
| return ret.first(); |
| #endif //QT_NO_PHONON_SETTINGSGROUP |
| return -1; |
| } |
| |
| #ifndef QT_NO_PHONON_AUDIOCAPTURE |
| void GlobalConfig::setAudioCaptureDeviceListFor(Phonon::Category category, QList<int> order) |
| { |
| #ifndef QT_NO_PHONON_SETTINGSGROUP |
| PulseSupport *pulse = PulseSupport::getInstance(); |
| if (pulse->isActive()) { |
| pulse->setCaptureDevicePriorityForCategory(category, order); |
| return; |
| } |
| |
| K_D(GlobalConfig); |
| QSettingsGroup backendConfig(&d->config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier()); |
| |
| order = reindexList(this, category, order, false); |
| |
| const QList<int> noCategoryOrder = audioCaptureDeviceListFor(Phonon::NoCategory, ShowUnavailableDevices|ShowAdvancedDevices); |
| if (category != Phonon::NoCategory && order == noCategoryOrder) { |
| backendConfig.removeEntry(QLatin1String("Category_") + QString::number(category)); |
| } else { |
| backendConfig.setValue(QLatin1String("Category_") + QString::number(category), order); |
| } |
| } |
| |
| QList<int> GlobalConfig::audioCaptureDeviceListFor(Phonon::Category category, int override) const |
| { |
| K_D(const GlobalConfig); |
| |
| const bool hide = ((override & AdvancedDevicesFromSettings) |
| ? hideAdvancedDevices() |
| : static_cast<bool>(override & HideAdvancedDevices)); |
| |
| QList<int> defaultList; |
| |
| PulseSupport *pulse = PulseSupport::getInstance(); |
| if (pulse->isActive()) { |
| defaultList = pulse->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); |
| if (hide || (override & HideUnavailableDevices)) { |
| filter(AudioCaptureDeviceType, NULL, &defaultList, |
| (hide ? FilterAdvancedDevices : 0) |
| | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) |
| ); |
| } |
| } else { |
| BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend()); |
| |
| #ifndef QT_NO_PHONON_PLATFORMPLUGIN |
| #else //QT_NO_SETTINGSGROUP |
| return QList<int>(); |
| #endif //QT_NO_SETTINGSGROUP |
| if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) { |
| // the platform plugin lists the audio devices for the platform |
| // this list already is in default order (as defined by the platform plugin) |
| defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); |
| if (hide) { |
| QMutableListIterator<int> it(defaultList); |
| while (it.hasNext()) { |
| AudioCaptureDevice objDesc = AudioCaptureDevice::fromIndex(it.next()); |
| const QVariant var = objDesc.property("isAdvanced"); |
| if (var.isValid() && var.toBool()) { |
| it.remove(); |
| } |
| } |
| } |
| } |
| #endif //QT_NO_PHONON_PLATFORMPLUGIN |
| |
| // lookup the available devices directly from the backend |
| if (backendIface) { |
| // this list already is in default order (as defined by the backend) |
| QList<int> list = backendIface->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType); |
| if (hide || !defaultList.isEmpty() || (override & HideUnavailableDevices)) { |
| filter(AudioCaptureDeviceType, backendIface, &list, |
| (hide ? FilterAdvancedDevices : 0) |
| // the platform plugin maybe already provided the hardware devices? |
| | (defaultList.isEmpty() ? 0 : FilterHardwareDevices) |
| | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0) |
| ); |
| } |
| defaultList += list; |
| } |
| } |
| |
| const QSettingsGroup backendConfig(&d->config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier()); |
| return sortDevicesByCategoryPriority(this, &backendConfig, AudioCaptureDeviceType, category, defaultList); |
| } |
| |
| int GlobalConfig::audioCaptureDeviceFor(Phonon::Category category, int override) const |
| { |
| QList<int> ret = audioCaptureDeviceListFor(category, override); |
| if (ret.isEmpty()) |
| return -1; |
| return ret.first(); |
| } |
| #endif //QT_NO_PHONON_AUDIOCAPTURE |
| |
| |
| } // namespace Phonon |
| |
| QT_END_NAMESPACE |