Qt 4.8
qaudiodeviceinfo_alsa_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtMultimedia module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
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 
54 
55 #include <alsa/version.h>
56 
58 
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 
72 {
73  close();
74 }
75 
77 {
78  return testSettings(format);
79 }
80 
82 {
84  if(mode == QAudio::AudioOutput) {
85  nearest.setFrequency(44100);
86  nearest.setChannels(2);
89  nearest.setSampleSize(16);
90  nearest.setCodec(QLatin1String("audio/pcm"));
91  } else {
92  nearest.setFrequency(8000);
93  nearest.setChannels(1);
95  nearest.setSampleSize(8);
96  nearest.setCodec(QLatin1String("audio/pcm"));
97  if(!testSettings(nearest)) {
98  nearest.setChannels(2);
99  nearest.setSampleSize(16);
101  }
102  }
103  return nearest;
104 }
105 
107 {
108  if(testSettings(format))
109  return format;
110  else
111  return preferredFormat();
112 }
113 
115 {
116  return device;
117 }
118 
120 {
121  updateLists();
122  return codecz;
123 }
124 
126 {
127  updateLists();
128  return freqz;
129 }
130 
132 {
133  updateLists();
134  return channelz;
135 }
136 
138 {
139  updateLists();
140  return sizez;
141 }
142 
144 {
145  updateLists();
146  return byteOrderz;
147 }
148 
150 {
151  updateLists();
152  return typez;
153 }
154 
156 {
157  int err = 0;
158  QString dev = device;
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 
197 {
198  if(handle)
199  snd_pcm_close(handle);
200  handle = 0;
201 }
202 
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 
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 
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)
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);
412  codecz.append(QLatin1String("audio/pcm"));
413  close();
414 }
415 
417 {
418  QList<QByteArray> allDevices;
419  QList<QByteArray> devices;
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))) {
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 
484 {
486  if(devices.size() == 0)
487  return QByteArray();
488 
489  return devices.first();
490 }
491 
493 {
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)
502 void 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)) {
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 
QBool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:904
static QByteArray defaultOutputDevice()
const unsigned int MAX_SAMPLE_RATES
int frequency() const
Use sampleRate() instead.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const unsigned int SAMPLE_RATES[]
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
QString deviceName() const
Returns the audio device name.
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
void setSampleType(QAudioFormat::SampleType sampleType)
Sets the sampleType to sampleType.
The QString class provides a Unicode character string.
Definition: qstring.h:83
int sampleSize() const
Returns the current sample size value.
QList< QAudioFormat::SampleType > typez
QAudioFormat::Endian byteOrder() const
Returns the current byteOrder value.
static QByteArray defaultInputDevice()
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
QAudioFormat preferredFormat() const
Returns the nearest settings.
QAudioFormat::SampleType sampleType() const
Returns the current SampleType value.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void setChannels(int channels)
Use setChannelCount() instead.
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
QString codec() const
Returns the current codec value.
QList< int > channelsList()
Returns the list of currently available channels.
bool isFormatSupported(const QAudioFormat &format) const
Returns true if format is available from audio device.
Q_CORE_EXPORT void qWarning(const char *,...)
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
void clear()
Removes all items from the list.
Definition: qlist.h:764
QByteArray toLocal8Bit() const Q_REQUIRED_RESULT
Returns the local 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4049
QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode)
Mode
Definition: qaudio.h:60
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
QStringList codecList()
Returns the list of currently available codecs.
QList< QAudioFormat::SampleType > sampleTypeList()
Returns the list of currently available sample types.
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
int compare(const QString &s) const
Definition: qstring.cpp:5037
QAudioFormat nearestFormat(const QAudioFormat &format) const
Returns the nearest settings format.
QList< QAudioFormat::Endian > byteOrderz
QList< QAudioFormat::Endian > byteOrderList()
Returns the list of currently available byte orders.
QList< int > sampleSizeList()
Returns the list of currently available sample sizes.
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
void setFrequency(int frequency)
Use setSampleRate() instead.
QList< int > frequencyList()
Returns the list of currently available frequencies.
int qstrcmp(const QByteArray &str1, const char *str2)
Definition: qbytearray.cpp:336
The QAudioFormat class stores audio parameter information.
Definition: qaudioformat.h:60
static QList< QByteArray > availableDevices(QAudio::Mode)
bool testSettings(const QAudioFormat &format) const
void setSampleSize(int sampleSize)
Sets the sample size to the sampleSize specified.
void setCodec(const QString &codec)
Sets the codec to codec.
void setByteOrder(QAudioFormat::Endian byteOrder)
Sets the byteOrder to byteOrder.
int channels() const
Use channelCount() instead.