source: smplayer/trunk/src/deviceinfo.cpp

Last change on this file was 189, checked in by Silvan Scherrer, 8 years ago

SMPlayer: adjust version info in readme and some small glitches

  • Property svn:eol-style set to LF
File size: 10.2 KB
Line 
1/* smplayer, GUI front-end for mplayer.
2 Copyright (C) 2006-2017 Ricardo Villalba <rvm@users.sourceforge.net>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18
19#include "deviceinfo.h"
20#include "paths.h"
21#include <QProcess>
22#include <QFile>
23#include <QSettings>
24#include <QDebug>
25
26#ifdef Q_OS_WIN
27
28#define USE_DIRECTX
29
30#ifdef USE_DIRECTX
31#define DIRECTSOUND_VERSION 5
32#include <dsound.h>
33#include <ddraw.h>
34
35QStringList dsound_device_list;
36QStringList ddraw_device_list;
37
38BOOL CALLBACK DirectSoundEnum(LPGUID guid, LPCSTR desc, LPCSTR module, LPVOID context)
39{
40 Q_UNUSED(guid);
41 Q_UNUSED(module);
42 Q_UNUSED(context);
43
44 dsound_device_list << QString(desc);
45 return TRUE;
46}
47
48BOOL WINAPI DirectDrawEnum(GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext, HMONITOR hm)
49{
50 Q_UNUSED(lpDriverName);
51 Q_UNUSED(lpContext);
52 Q_UNUSED(hm);
53
54 if (!lpGUID) {
55 ddraw_device_list << "Primary Display Adapter";
56 } else {
57 ddraw_device_list << QString(lpDriverDescription);
58 }
59 return TRUE;
60}
61
62
63DeviceList DeviceInfo::retrieveDevices(DeviceType type) {
64 qDebug("DeviceInfo::retrieveDevices: %d", type);
65
66 DeviceList l;
67
68 dsound_device_list.clear();
69 ddraw_device_list.clear();
70
71 if (type == Sound) {
72 DirectSoundEnumerateA(DirectSoundEnum, NULL);
73 for (int n = 0; n < dsound_device_list.count(); n++) {
74 QString desc = dsound_device_list[n];
75 qDebug() << "DeviceInfo::retrieveDevices: audio:" << n << desc;
76 l.append( DeviceData(n, desc) );
77 }
78 }
79 else
80 if (type == Display) {
81 DirectDrawEnumerateExA(DirectDrawEnum, NULL, DDENUM_ATTACHEDSECONDARYDEVICES);
82 for (int n = 0; n < ddraw_device_list.count(); n++) {
83 QString desc = ddraw_device_list[n];
84 qDebug() << "DeviceInfo::retrieveDevices: display:" << n << desc;
85 l.append( DeviceData(n, desc) );
86 }
87 }
88
89 return l;
90}
91
92#else
93
94DeviceList DeviceInfo::retrieveDevices(DeviceType type) {
95 qDebug("DeviceInfo::retrieveDevices: %d", type);
96
97 DeviceList l;
98
99 #ifdef CACHE_DEVICE_INFO
100 QString inifile = Paths::configPath() + "/device_info.ini";
101 QSettings set(inifile, QSettings::IniFormat);
102 QString section_name = "display-devices";
103 if (type == Sound) section_name = "dsound-devices";
104
105 // Check if we already have the list stored in the INI file
106 l = loadList(&set, section_name);
107 if (l.count() > 0) return l;
108 #endif
109
110 QRegExp rx_device("^(\\d+): (.*)");
111
112 if (QFile::exists("dxlist.exe")) {
113 QProcess p;
114 p.setProcessChannelMode( QProcess::MergedChannels );
115 QStringList arg;
116 if (type == Sound) arg << "-s"; else arg << "-d";
117 p.start("dxlist", arg);
118
119 if (p.waitForFinished()) {
120 QByteArray line;
121 while (p.canReadLine()) {
122 line = p.readLine().trimmed();
123 qDebug("DeviceInfo::retrieveDevices: '%s'", line.constData());
124 if ( rx_device.indexIn(line) > -1 ) {
125 int id = rx_device.cap(1).toInt();
126 QString desc = rx_device.cap(2);
127 qDebug("DeviceInfo::retrieveDevices: found device: '%d' '%s'", id, desc.toUtf8().constData());
128 l.append( DeviceData(id, desc) );
129 }
130 }
131 }
132 }
133
134 #ifdef CACHE_DEVICE_INFO
135 saveList(&set, section_name, l);
136 #endif
137
138 return l;
139}
140#endif
141
142DeviceList DeviceInfo::dsoundDevices() {
143 return retrieveDevices(Sound);
144}
145
146DeviceList DeviceInfo::displayDevices() {
147 return retrieveDevices(Display);
148}
149
150#else
151
152// Linux
153
154#if USE_PULSEAUDIO_DEVICES
155DeviceList DeviceInfo::paDevices() {
156 qDebug("DeviceInfo::paDevices");
157
158 static DeviceList l;
159 if (!l.isEmpty()) return l;
160
161 QRegExp rx_index("(.*)index: (\\d+)");
162 QRegExp rx_name("(.*)name: (.*)");
163
164 QProcess p;
165 p.setProcessChannelMode( QProcess::MergedChannels );
166 QStringList env = QProcess::systemEnvironment();
167 env << "LC_ALL=C";
168 p.setEnvironment(env);
169 p.start("pacmd list-sinks");
170
171 int index = -1;
172 QString name;
173
174 if (p.waitForFinished()) {
175 QByteArray line;
176 while (p.canReadLine()) {
177 line = p.readLine().trimmed();
178 //qDebug() << "DeviceInfo::paDevices:" << line;
179 if (rx_index.indexIn(line) > -1 ) {
180 index = rx_index.cap(2).toInt();
181 qDebug() << "DeviceInfo::paDevices: index:" << index;
182 }
183 if (rx_name.indexIn(line) > -1 ) {
184 name = rx_name.cap(2);
185 if (name.startsWith('<') && name.endsWith('>')) { name = name.mid(1); name.chop(1); }
186 qDebug() << "DeviceInfo::paDevices: name:" << name;
187 if (index != -1) {
188 l.append( DeviceData(index, name) );
189 index = -1;
190 }
191 }
192 }
193 }
194
195 return l;
196}
197#endif // USE_PULSEAUDIO_DEVICES
198
199#if USE_ALSA_DEVICES
200DeviceList DeviceInfo::alsaDevices() {
201 qDebug("DeviceInfo::alsaDevices");
202
203 DeviceList l;
204
205 #ifdef CACHE_DEVICE_INFO
206 QString inifile = Paths::configPath() + "/device_info.ini";
207 QSettings set(inifile, QSettings::IniFormat);
208
209 // Check if we already have the list stored in the INI file
210 l = loadList(&set, "alsa-devices");
211 if (l.count() > 0) return l;
212 #endif
213
214 QRegExp rx_device("^card\\s([0-9]+).*\\[(.*)\\],\\sdevice\\s([0-9]+):");
215
216 QProcess p;
217 p.setProcessChannelMode( QProcess::MergedChannels );
218 p.setEnvironment( QStringList() << "LC_ALL=C" );
219 p.start("aplay", QStringList() << "-l");
220
221 if (p.waitForFinished()) {
222 QByteArray line;
223 while (p.canReadLine()) {
224 line = p.readLine();
225 qDebug("DeviceInfo::alsaDevices: '%s'", line.constData());
226 if ( rx_device.indexIn(line) > -1 ) {
227 QString id = rx_device.cap(1);
228 id.append(".");
229 id.append(rx_device.cap(3));
230 QString desc = rx_device.cap(2);
231 qDebug("DeviceInfo::alsaDevices: found device: '%s' '%s'", id.toUtf8().constData(), desc.toUtf8().constData());
232 l.append( DeviceData(id, desc) );
233 }
234 }
235 } else {
236 qDebug("DeviceInfo::alsaDevices: could not start aplay, error %d", p.error());
237 }
238
239 #ifdef CACHE_DEVICE_INFO
240 saveList(&set, "alsa-devices", l);
241 #endif
242
243 return l;
244}
245#endif
246
247#if USE_XV_ADAPTORS
248DeviceList DeviceInfo::xvAdaptors() {
249 qDebug("DeviceInfo::xvAdaptors");
250
251 DeviceList l;
252
253 #ifdef CACHE_DEVICE_INFO
254 QString inifile = Paths::configPath() + "/device_info.ini";
255 QSettings set(inifile, QSettings::IniFormat);
256
257 // Check if we already have the list stored in the INI file
258 l = loadList(&set, "xv-adaptors");
259 if (l.count() > 0) return l;
260 #endif
261
262 QRegExp rx_device("^.*Adaptor #([0-9]+): \"(.*)\"");
263
264 QProcess p;
265 p.setProcessChannelMode( QProcess::MergedChannels );
266 p.setEnvironment( QProcess::systemEnvironment() << "LC_ALL=C" );
267 p.start("xvinfo");
268
269 if (p.waitForFinished()) {
270 QByteArray line;
271 while (p.canReadLine()) {
272 line = p.readLine();
273 qDebug("DeviceInfo::xvAdaptors: '%s'", line.constData());
274 if ( rx_device.indexIn(line) > -1 ) {
275 QString id = rx_device.cap(1);
276 QString desc = rx_device.cap(2);
277 qDebug("DeviceInfo::xvAdaptors: found adaptor: '%s' '%s'", id.toUtf8().constData(), desc.toUtf8().constData());
278 l.append( DeviceData(id, desc) );
279 }
280 }
281 } else {
282 qDebug("DeviceInfo::xvAdaptors: could not start xvinfo, error %d", p.error());
283 }
284
285 #ifdef CACHE_DEVICE_INFO
286 saveList(&set, "xv-adaptors", l);
287 #endif
288
289 return l;
290}
291#endif
292#endif
293
294#if MPV_AUDIO_DEVICES
295QString DeviceInfo::mpv_bin;
296
297#if USE_MPV_ALSA_DEVICES
298DeviceList DeviceInfo::mpvAlsaDevices() {
299 static DeviceList l;
300 if (!l.isEmpty()) return l;
301 l = mpvAudioDevices("alsa");
302 return l;
303}
304#endif
305
306#if USE_MPV_WASAPI_DEVICES
307DeviceList DeviceInfo::mpvWasapiDevices() {
308 static DeviceList l;
309 if (!l.isEmpty()) return l;
310 l = mpvAudioDevices("wasapi");
311 return l;
312}
313#endif
314
315DeviceList DeviceInfo::mpvAudioDevices(const QString & filter) {
316 DeviceList l;
317 if (!mpv_bin.isEmpty()) l = mpvAudioDevices(mpv_bin, filter);
318 return l;
319}
320
321DeviceList DeviceInfo::mpvAudioDevices(const QString & mpv_bin, const QString & filter) {
322 qDebug("DeviceInfo::mpvAudioDevices");
323
324 DeviceList l;
325
326 QRegExp rx("'" + filter + "\\/(.*)'\\s+\\((.*)\\)");
327
328 QProcess p;
329 p.setProcessChannelMode( QProcess::MergedChannels );
330
331 p.start(mpv_bin, QStringList() << "--audio-device=help");
332
333 QString device;
334 QString name;
335 //int index = 0;
336
337 if (p.waitForFinished()) {
338 QString line;
339 while (p.canReadLine()) {
340 line = QString::fromUtf8(p.readLine().trimmed());
341 qDebug() << "DeviceInfo::mpvAudioDevices:" << line;
342
343 if (rx.indexIn(line) > -1 ) {
344 device = rx.cap(1);
345 name = rx.cap(2);
346 qDebug() << "DeviceInfo::mpvAudioDevices: device:" << device << "name:" << name;
347 l.append( DeviceData(device, name) );
348 //index++;
349 }
350 }
351 }
352
353 return l;
354}
355#endif
356
357#ifdef CACHE_DEVICE_INFO
358void DeviceInfo::saveList(QSettings * set, const QString & section_name, const DeviceList & list) {
359 set->beginWriteArray(section_name);
360 for (int i = 0; i < list.count(); ++i) {
361 set->setArrayIndex(i);
362 set->setValue("ID", list.at(i).ID());
363 set->setValue("description", list.at(i).desc());
364 }
365 set->endArray();
366}
367
368DeviceList DeviceInfo::loadList(QSettings * set, const QString & section_name) {
369 DeviceList l;
370
371 int count = set->beginReadArray(section_name);
372 for (int i = 0; i < count; ++i) {
373 set->setArrayIndex(i);
374 QVariant id = set->value("ID");
375 QString desc = set->value("description", "").toString();
376 l.append(DeviceData(id, desc));
377 }
378
379 set->endArray();
380
381 return l;
382}
383#endif
384
385QString DeviceInfo::printableName(const QString & driver_name, const DeviceData & device) {
386 return printableName(driver_name, device.ID().toString(), device.desc());
387}
388
389QString DeviceInfo::internalName(const QString & driver_name, const DeviceData & device) {
390 return internalName(driver_name, device.ID().toString(), device.desc());
391}
392
393QString DeviceInfo::printableName(const QString & driver_name, const QString & id, const QString & desc) {
394 Q_UNUSED(id);
395 return driver_name +" (" + /* id + " - " + */ desc + ")";
396}
397
398QString DeviceInfo::internalName(const QString & driver_name, const QString & id, const QString & desc) {
399 return driver_name + ":::" + id + ":::" + desc;
400}
401
402QStringList DeviceInfo::extractDevice(const QString & internal_name) {
403 return internal_name.split(":::");
404}
Note: See TracBrowser for help on using the repository browser.