source: trunk/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 17.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtMultimedia module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//
43// W A R N I N G
44// -------------
45//
46// This file is not part of the Qt API. It exists for the convenience
47// of other Qt classes. This header file may change from version to
48// version without notice, or even be removed.
49//
50// We mean it.
51//
52
53#include "qaudiodeviceinfo_alsa_p.h"
54
55#include <alsa/version.h>
56
57QT_BEGIN_NAMESPACE
58
59QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode)
60{
61 handle = 0;
62
63 device = QLatin1String(dev);
64 this->mode = mode;
65
66#if (SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
67 checkSurround();
68#endif
69}
70
71QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal()
72{
73 close();
74}
75
76bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
77{
78 return testSettings(format);
79}
80
81QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
82{
83 QAudioFormat nearest;
84 if(mode == QAudio::AudioOutput) {
85 nearest.setFrequency(44100);
86 nearest.setChannels(2);
87 nearest.setByteOrder(QAudioFormat::LittleEndian);
88 nearest.setSampleType(QAudioFormat::SignedInt);
89 nearest.setSampleSize(16);
90 nearest.setCodec(QLatin1String("audio/pcm"));
91 } else {
92 nearest.setFrequency(8000);
93 nearest.setChannels(1);
94 nearest.setSampleType(QAudioFormat::UnSignedInt);
95 nearest.setSampleSize(8);
96 nearest.setCodec(QLatin1String("audio/pcm"));
97 if(!testSettings(nearest)) {
98 nearest.setChannels(2);
99 nearest.setSampleSize(16);
100 nearest.setSampleType(QAudioFormat::SignedInt);
101 }
102 }
103 return nearest;
104}
105
106QAudioFormat QAudioDeviceInfoInternal::nearestFormat(const QAudioFormat& format) const
107{
108 if(testSettings(format))
109 return format;
110 else
111 return preferredFormat();
112}
113
114QString QAudioDeviceInfoInternal::deviceName() const
115{
116 return device;
117}
118
119QStringList QAudioDeviceInfoInternal::codecList()
120{
121 updateLists();
122 return codecz;
123}
124
125QList<int> QAudioDeviceInfoInternal::frequencyList()
126{
127 updateLists();
128 return freqz;
129}
130
131QList<int> QAudioDeviceInfoInternal::channelsList()
132{
133 updateLists();
134 return channelz;
135}
136
137QList<int> QAudioDeviceInfoInternal::sampleSizeList()
138{
139 updateLists();
140 return sizez;
141}
142
143QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::byteOrderList()
144{
145 updateLists();
146 return byteOrderz;
147}
148
149QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::sampleTypeList()
150{
151 updateLists();
152 return typez;
153}
154
155bool QAudioDeviceInfoInternal::open()
156{
157 int err = 0;
158 QString dev = device;
159 QList<QByteArray> devices = availableDevices(mode);
160
161 if(dev.compare(QLatin1String("default")) == 0) {
162#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
163 dev = QLatin1String(devices.first().constData());
164#else
165 dev = QLatin1String("hw:0,0");
166#endif
167 } else {
168#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
169 dev = device;
170#else
171 int idx = 0;
172 char *name;
173
174 QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);
175
176 while(snd_card_get_name(idx,&name) == 0) {
177 if(dev.contains(QLatin1String(name)))
178 break;
179 idx++;
180 }
181 dev = QString(QLatin1String("hw:%1,0")).arg(idx);
182#endif
183 }
184 if(mode == QAudio::AudioOutput) {
185 err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
186 } else {
187 err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
188 }
189 if(err < 0) {
190 handle = 0;
191 return false;
192 }
193 return true;
194}
195
196void QAudioDeviceInfoInternal::close()
197{
198 if(handle)
199 snd_pcm_close(handle);
200 handle = 0;
201}
202
203bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
204{
205 // Set nearest to closest settings that do work.
206 // See if what is in settings will work (return value).
207 int err = 0;
208 snd_pcm_t* handle;
209 snd_pcm_hw_params_t *params;
210 QString dev = device;
211
212 QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);
213
214 if(dev.compare(QLatin1String("default")) == 0) {
215#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
216 dev = QLatin1String(devices.first().constData());
217#else
218 dev = QLatin1String("hw:0,0");
219#endif
220 } else {
221#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
222 dev = device;
223#else
224 int idx = 0;
225 char *name;
226
227 QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);
228
229 while(snd_card_get_name(idx,&name) == 0) {
230 if(shortName.compare(QLatin1String(name)) == 0)
231 break;
232 idx++;
233 }
234 dev = QString(QLatin1String("hw:%1,0")).arg(idx);
235#endif
236 }
237 if(mode == QAudio::AudioOutput) {
238 err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
239 } else {
240 err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
241 }
242 if(err < 0) {
243 handle = 0;
244 return false;
245 }
246
247 bool testChannel = false;
248 bool testCodec = false;
249 bool testFreq = false;
250 bool testType = false;
251 bool testSize = false;
252
253 int dir = 0;
254
255 snd_pcm_nonblock( handle, 0 );
256 snd_pcm_hw_params_alloca( &params );
257 snd_pcm_hw_params_any( handle, params );
258
259 // set the values!
260 snd_pcm_hw_params_set_channels(handle,params,format.channels());
261 snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
262
263 err = -1;
264
265 switch(format.sampleSize()) {
266 case 8:
267 if(format.sampleType() == QAudioFormat::SignedInt)
268 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
269 else if(format.sampleType() == QAudioFormat::UnSignedInt)
270 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
271 break;
272 case 16:
273 if(format.sampleType() == QAudioFormat::SignedInt) {
274 if(format.byteOrder() == QAudioFormat::LittleEndian)
275 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
276 else if(format.byteOrder() == QAudioFormat::BigEndian)
277 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
278 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
279 if(format.byteOrder() == QAudioFormat::LittleEndian)
280 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
281 else if(format.byteOrder() == QAudioFormat::BigEndian)
282 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
283 }
284 break;
285 case 32:
286 if(format.sampleType() == QAudioFormat::SignedInt) {
287 if(format.byteOrder() == QAudioFormat::LittleEndian)
288 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
289 else if(format.byteOrder() == QAudioFormat::BigEndian)
290 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
291 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
292 if(format.byteOrder() == QAudioFormat::LittleEndian)
293 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
294 else if(format.byteOrder() == QAudioFormat::BigEndian)
295 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
296 }
297 }
298
299 // For now, just accept only audio/pcm codec
300 if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
301 err=-1;
302 } else
303 testCodec = true;
304
305 if(err>=0 && format.channels() != -1) {
306 err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
307 if(err>=0)
308 err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
309 if(err>=0)
310 testChannel = true;
311 }
312
313 if(err>=0 && format.frequency() != -1) {
314 err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
315 if(err>=0)
316 err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
317 if(err>=0)
318 testFreq = true;
319 }
320
321 if((err>=0 && format.sampleSize() != -1) &&
322 (format.sampleType() != QAudioFormat::Unknown)) {
323 switch(format.sampleSize()) {
324 case 8:
325 if(format.sampleType() == QAudioFormat::SignedInt)
326 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
327 else if(format.sampleType() == QAudioFormat::UnSignedInt)
328 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
329 break;
330 case 16:
331 if(format.sampleType() == QAudioFormat::SignedInt) {
332 if(format.byteOrder() == QAudioFormat::LittleEndian)
333 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
334 else if(format.byteOrder() == QAudioFormat::BigEndian)
335 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
336 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
337 if(format.byteOrder() == QAudioFormat::LittleEndian)
338 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
339 else if(format.byteOrder() == QAudioFormat::BigEndian)
340 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
341 }
342 break;
343 case 32:
344 if(format.sampleType() == QAudioFormat::SignedInt) {
345 if(format.byteOrder() == QAudioFormat::LittleEndian)
346 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
347 else if(format.byteOrder() == QAudioFormat::BigEndian)
348 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
349 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
350 if(format.byteOrder() == QAudioFormat::LittleEndian)
351 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
352 else if(format.byteOrder() == QAudioFormat::BigEndian)
353 err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
354 }
355 }
356 if(err>=0) {
357 testSize = true;
358 testType = true;
359 }
360 }
361 if(err>=0)
362 err = snd_pcm_hw_params(handle, params);
363
364 if(err == 0) {
365 // settings work
366 // close()
367 if(handle)
368 snd_pcm_close(handle);
369 return true;
370 }
371 if(handle)
372 snd_pcm_close(handle);
373
374 return false;
375}
376
377void QAudioDeviceInfoInternal::updateLists()
378{
379 // redo all lists based on current settings
380 freqz.clear();
381 channelz.clear();
382 sizez.clear();
383 byteOrderz.clear();
384 typez.clear();
385 codecz.clear();
386
387 if(!handle)
388 open();
389
390 if(!handle)
391 return;
392
393 for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) {
394 //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
395 freqz.append(SAMPLE_RATES[i]);
396 }
397 channelz.append(1);
398 channelz.append(2);
399#if (SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
400 if (surround40) channelz.append(4);
401 if (surround51) channelz.append(6);
402 if (surround71) channelz.append(8);
403#endif
404 sizez.append(8);
405 sizez.append(16);
406 sizez.append(32);
407 byteOrderz.append(QAudioFormat::LittleEndian);
408 byteOrderz.append(QAudioFormat::BigEndian);
409 typez.append(QAudioFormat::SignedInt);
410 typez.append(QAudioFormat::UnSignedInt);
411 typez.append(QAudioFormat::Float);
412 codecz.append(QLatin1String("audio/pcm"));
413 close();
414}
415
416QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode)
417{
418 QList<QByteArray> allDevices;
419 QList<QByteArray> devices;
420 QByteArray filter;
421
422#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
423 // Create a list of all current audio devices that support mode
424 void **hints, **n;
425 char *name, *descr, *io;
426
427 if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
428 qWarning() << "no alsa devices available";
429 return devices;
430 }
431 n = hints;
432
433 if(mode == QAudio::AudioInput) {
434 filter = "Input";
435 } else {
436 filter = "Output";
437 }
438
439 while (*n != NULL) {
440 name = snd_device_name_get_hint(*n, "NAME");
441 if (name != 0 && qstrcmp(name, "null") != 0) {
442 descr = snd_device_name_get_hint(*n, "DESC");
443 io = snd_device_name_get_hint(*n, "IOID");
444
445 if ((descr != NULL) && ((io == NULL) || (io == filter))) {
446 QString deviceName = QLatin1String(name);
447 QString deviceDescription = QLatin1String(descr);
448 allDevices.append(deviceName.toLocal8Bit().constData());
449 if (deviceDescription.contains(QLatin1String("Default Audio Device")))
450 devices.append(deviceName.toLocal8Bit().constData());
451 }
452
453 free(name);
454 if (descr != NULL)
455 free(descr);
456 if (io != NULL)
457 free(io);
458 }
459 ++n;
460 }
461 snd_device_name_free_hint(hints);
462
463 if(devices.size() > 0) {
464 devices.append("default");
465 }
466#else
467 int idx = 0;
468 char* name;
469
470 while(snd_card_get_name(idx,&name) == 0) {
471 devices.append(name);
472 idx++;
473 }
474 if (idx > 0)
475 devices.append("default");
476#endif
477 if (devices.size() == 0 && allDevices.size() > 0)
478 return allDevices;
479
480 return devices;
481}
482
483QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
484{
485 QList<QByteArray> devices = availableDevices(QAudio::AudioInput);
486 if(devices.size() == 0)
487 return QByteArray();
488
489 return devices.first();
490}
491
492QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
493{
494 QList<QByteArray> devices = availableDevices(QAudio::AudioOutput);
495 if(devices.size() == 0)
496 return QByteArray();
497
498 return devices.first();
499}
500
501#if (SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
502void QAudioDeviceInfoInternal::checkSurround()
503{
504 QList<QByteArray> devices;
505 surround40 = false;
506 surround51 = false;
507 surround71 = false;
508
509 void **hints, **n;
510 char *name, *descr, *io;
511
512 if(snd_device_name_hint(-1, "pcm", &hints) < 0)
513 return;
514
515 n = hints;
516
517 while (*n != NULL) {
518 name = snd_device_name_get_hint(*n, "NAME");
519 descr = snd_device_name_get_hint(*n, "DESC");
520 io = snd_device_name_get_hint(*n, "IOID");
521 if((name != NULL) && (descr != NULL)) {
522 QString deviceName = QLatin1String(name);
523 if (mode == QAudio::AudioOutput) {
524 if(deviceName.contains(QLatin1String("surround40")))
525 surround40 = true;
526 if(deviceName.contains(QLatin1String("surround51")))
527 surround51 = true;
528 if(deviceName.contains(QLatin1String("surround71")))
529 surround71 = true;
530 }
531 }
532 if(name != NULL)
533 free(name);
534 if(descr != NULL)
535 free(descr);
536 if(io != NULL)
537 free(io);
538 ++n;
539 }
540 snd_device_name_free_hint(hints);
541}
542#endif
543
544QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.