File indexing completed on 2024-12-01 04:21:25
0001 /* 0002 Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com> 0003 Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com> 0004 Copyright (C) 2009 Fathi Boudra <fabo@kde.org> 0005 Copyright (C) 2009-2010 vlc-phonon AUTHORS <kde-multimedia@kde.org> 0006 Copyright (C) 2011 Harald Sitter <sitter@kde.org> 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Lesser General Public 0010 License as published by the Free Software Foundation; either 0011 version 2.1 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Lesser General Public License for more details. 0017 0018 You should have received a copy of the GNU Lesser General Public 0019 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0020 */ 0021 0022 #include "devicemanager.h" 0023 0024 #include <phonon/pulsesupport.h> 0025 0026 #include <vlc/vlc.h> 0027 0028 #include "backend.h" 0029 #include "utils/debug.h" 0030 #include "utils/libvlc.h" 0031 #include "utils/vstring.h" 0032 0033 namespace Phonon 0034 { 0035 namespace VLC 0036 { 0037 0038 /* 0039 * Device Info 0040 */ 0041 0042 DeviceInfo::DeviceInfo(const QString &name, bool isAdvanced) 0043 { 0044 // Get an id 0045 static int counter = 0; 0046 m_id = counter++; 0047 0048 // Get name and description for the device 0049 m_name = name; 0050 m_isAdvanced = isAdvanced; 0051 m_capabilities = None; 0052 0053 // A default device should never be advanced 0054 if (name.startsWith(QLatin1String("default"), Qt::CaseInsensitive)) 0055 m_isAdvanced = false; 0056 } 0057 0058 int DeviceInfo::id() const 0059 { 0060 return m_id; 0061 } 0062 0063 const QString& DeviceInfo::name() const 0064 { 0065 return m_name; 0066 } 0067 0068 const QString& DeviceInfo::description() const 0069 { 0070 return m_description; 0071 } 0072 0073 bool DeviceInfo::isAdvanced() const 0074 { 0075 return m_isAdvanced; 0076 } 0077 0078 void DeviceInfo::setAdvanced(bool advanced) 0079 { 0080 m_isAdvanced = advanced; 0081 } 0082 0083 const DeviceAccessList& DeviceInfo::accessList() const 0084 { 0085 return m_accessList; 0086 } 0087 0088 void DeviceInfo::addAccess(const DeviceAccess& access) 0089 { 0090 if (m_accessList.isEmpty()) 0091 m_description = access.first + ": " + access.second; 0092 m_accessList.append(access); 0093 } 0094 0095 quint16 DeviceInfo::capabilities() const 0096 { 0097 return m_capabilities; 0098 } 0099 0100 void DeviceInfo::setCapabilities(quint16 cap) 0101 { 0102 m_capabilities = cap; 0103 } 0104 0105 0106 /* 0107 * Device Manager 0108 */ 0109 0110 DeviceManager::DeviceManager(Backend *parent) 0111 : QObject(parent) 0112 , m_backend(parent) 0113 { 0114 Q_ASSERT(parent); 0115 updateDeviceList(); 0116 } 0117 0118 DeviceManager::~DeviceManager() 0119 { 0120 } 0121 0122 QList<int> DeviceManager::deviceIds(ObjectDescriptionType type) 0123 { 0124 DeviceInfo::Capability capability = DeviceInfo::None; 0125 switch (type) { 0126 case Phonon::AudioOutputDeviceType: 0127 capability = DeviceInfo::AudioOutput; 0128 break; 0129 case Phonon::AudioCaptureDeviceType: 0130 capability = DeviceInfo::AudioCapture; 0131 break; 0132 case Phonon::VideoCaptureDeviceType: 0133 capability = DeviceInfo::VideoCapture; 0134 break; 0135 default: ; 0136 } 0137 0138 QList<int> ids; 0139 foreach (const DeviceInfo &device, m_devices) { 0140 if (device.capabilities() & capability) 0141 ids.append(device.id()); 0142 } 0143 0144 return ids; 0145 } 0146 0147 QHash<QByteArray, QVariant> DeviceManager::deviceProperties(int id) 0148 { 0149 QHash<QByteArray, QVariant> properties; 0150 0151 foreach (const DeviceInfo &device, m_devices) { 0152 if (device.id() == id) { 0153 properties.insert("name", device.name()); 0154 properties.insert("description", device.description()); 0155 properties.insert("isAdvanced", device.isAdvanced()); 0156 properties.insert("deviceAccessList", QVariant::fromValue<Phonon::DeviceAccessList>(device.accessList())); 0157 properties.insert("discovererIcon", "vlc"); 0158 0159 if (device.capabilities() & DeviceInfo::AudioOutput) { 0160 properties.insert("icon", QLatin1String("audio-card")); 0161 } 0162 0163 if (device.capabilities() & DeviceInfo::AudioCapture) { 0164 properties.insert("hasaudio", true); 0165 properties.insert("icon", QLatin1String("audio-input-microphone")); 0166 } 0167 0168 if (device.capabilities() & DeviceInfo::VideoCapture) { 0169 properties.insert("hasvideo", true); 0170 properties.insert("icon", QLatin1String("camera-web")); 0171 } 0172 break; 0173 } 0174 } 0175 0176 return properties; 0177 } 0178 0179 const DeviceInfo *DeviceManager::device(int id) const 0180 { 0181 for (int i = 0; i < m_devices.size(); i ++) { 0182 if (m_devices[i].id() == id) 0183 return &m_devices[i]; 0184 } 0185 0186 return NULL; 0187 } 0188 0189 static QList<QByteArray> vlcAudioOutBackends() 0190 { 0191 QList<QByteArray> ret; 0192 0193 VLC_FOREACH_LIST(audio_output, aout) { 0194 QByteArray name(aout->psz_name); 0195 if (!ret.contains(name)) 0196 ret.append(name); 0197 } 0198 0199 return ret; 0200 } 0201 0202 void DeviceManager::updateDeviceList() 0203 { 0204 QList<DeviceInfo> newDeviceList; 0205 0206 if (!LibVLC::self || !pvlc_libvlc) 0207 return; 0208 0209 QList<QByteArray> audioOutBackends = vlcAudioOutBackends(); 0210 0211 PulseSupport *pulse = PulseSupport::getInstance(); 0212 if (pulse && pulse->isUsable()) { 0213 if (audioOutBackends.contains("pulse")) { 0214 DeviceInfo defaultAudioOutputDevice(tr("Default"), false); 0215 defaultAudioOutputDevice.setCapabilities(DeviceInfo::AudioOutput); 0216 defaultAudioOutputDevice.addAccess(DeviceAccess("pulse", "default")); 0217 newDeviceList.append(defaultAudioOutputDevice); 0218 pulse->request(true); 0219 return; 0220 } else { 0221 pulse->enable(false); 0222 } 0223 } 0224 0225 QList<QByteArray> knownSoundSystems; 0226 // Whitelist - Order has no particular impact. 0227 // NOTE: if listing was not intercepted by the PA code above we also need 0228 // to try injecting the pulse aout as otherwise the user would have to 0229 // use the fake PA device in ALSA to output through PA (kind of silly). 0230 knownSoundSystems << QByteArray("pulse") 0231 << QByteArray("alsa") 0232 << QByteArray("oss") 0233 << QByteArray("jack") 0234 << QByteArray("aout_directx") // Windows up to VLC 2.0 0235 << QByteArray("directsound") // Windows from VLC 2.1 upwards 0236 << QByteArray("auhal"); // Mac 0237 foreach (const QByteArray &soundSystem, knownSoundSystems) { 0238 if (!audioOutBackends.contains(soundSystem)) { 0239 debug() << "Sound system" << soundSystem << "not supported by libvlc"; 0240 continue; 0241 } 0242 0243 // FIXME: there is a rather ungodly amount of code duplication going 0244 // on here. 0245 bool hasDevices = false; 0246 VLC_FOREACH(audio_output_device, 0247 device, 0248 libvlc_audio_output_device_list_get(pvlc_libvlc, soundSystem), 0249 libvlc_audio_output_device_list_release) { 0250 QString idName = QString::fromUtf8(device->psz_device); 0251 QString longName = QString::fromUtf8(device->psz_description); 0252 0253 debug() << "found device" << soundSystem << idName << longName; 0254 0255 DeviceInfo info(longName, true); 0256 info.addAccess(DeviceAccess(soundSystem, idName)); 0257 info.setCapabilities(DeviceInfo::AudioOutput); 0258 newDeviceList.append(info); 0259 0260 hasDevices = true; 0261 } 0262 0263 if (!hasDevices) { 0264 debug() << "manually injecting sound system" << soundSystem; 0265 DeviceInfo info(QString::fromUtf8(soundSystem), false); 0266 info.addAccess(DeviceAccess(soundSystem, "")); 0267 info.setCapabilities(DeviceInfo::AudioOutput); 0268 newDeviceList.append(info); 0269 } 0270 } 0271 0272 /* 0273 * Compares the list with the devices available at the moment with the last list. If 0274 * a new device is seen, a signal is emitted. If a device disappeared, another signal 0275 * is emitted. 0276 */ 0277 0278 // Search for added devices 0279 for (int i = 0; i < newDeviceList.count(); ++i) { 0280 int id = newDeviceList[i].id(); 0281 if (!listContainsDevice(m_devices, id)) { 0282 // This is a new device, add it 0283 m_devices.append(newDeviceList[i]); 0284 emit deviceAdded(id); 0285 0286 debug() << "Added backend device" << newDeviceList[i].name(); 0287 } 0288 } 0289 0290 // Search for removed devices 0291 for (int i = m_devices.count() - 1; i >= 0; --i) { 0292 int id = m_devices[i].id(); 0293 if (!listContainsDevice(newDeviceList, id)) { 0294 emit deviceRemoved(id); 0295 m_devices.removeAt(i); 0296 } 0297 } 0298 } 0299 0300 bool DeviceManager::listContainsDevice(const QList<DeviceInfo> &list, int id) 0301 { 0302 foreach (const DeviceInfo &d, list) { 0303 if (d.id() == id) 0304 return true; 0305 } 0306 return false; 0307 } 0308 0309 } 0310 }