kwave  18.07.70
Record-OSS.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  Record-OSS.cpp - device for audio recording via OSS
3  -------------------
4  begin : Sun Jul 24 2005
5  copyright : (C) 2005 by Thomas Eschenbacher
6  email : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "config.h"
19 #ifdef HAVE_OSS_SUPPORT
20 
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <math.h>
24 #include <sys/ioctl.h>
25 #include <sys/soundcard.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include <QDir>
31 #include <QFile>
32 #include <QLatin1Char>
33 #include <QtGlobal>
34 
35 #include "libkwave/Compression.h"
36 #include "libkwave/SampleFormat.h"
37 #include "libkwave/String.h"
38 #include "libkwave/Utils.h"
39 
40 #include "Record-OSS.h"
41 
42 // Linux 2.6.24 and above's OSS emulation supports 24 and 32 bit formats
43 // but did not declare them in <soundcard.h>
44 #ifndef AFMT_S24_LE
45 #define AFMT_S24_LE 0x00008000
46 #endif
47 #ifndef AFMT_S24_BE
48 #define AFMT_S24_BE 0x00010000
49 #endif
50 #ifndef AFMT_S32_LE
51 #define AFMT_S32_LE 0x00001000
52 #endif
53 #ifndef AFMT_S32_BE
54 #define AFMT_S32_BE 0x00002000
55 #endif
56 
57 #ifndef SNDCTL_DSP_SPEED
58 #define SNDCTL_DSP_SPEED SOUND_PCM_WRITE_RATE
59 #endif
60 
61 #ifndef SNDCTL_DSP_CHANNELS
62 #define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS
63 #endif
64 
65 #ifndef SOUND_PCM_SETFMT
66 #define SOUND_PCM_SETFMT SOUND_PCM_WRITE_BITS
67 #endif
68 
69 #ifndef SNDCTL_DSP_SETFMT
70 #define SNDCTL_DSP_SETFMT SOUND_PCM_SETFMT
71 #endif
72 
73 
74 #define MAX_CHANNELS 2
76 //***************************************************************************
78  :Kwave::RecordDevice(),
79  m_fd(-1), m_rate(0), m_tracks(0), m_oss_version(-1)
80 {
81 }
82 
83 //***************************************************************************
85 {
86  close();
87 }
88 
89 //***************************************************************************
90 QString Kwave::RecordOSS::open(const QString &dev)
91 {
92  // close the device if it is still open
93  if (m_fd >= 0) close();
94  if (!dev.length()) return QString::number(EINVAL); // no device name
95 
96  // first of all: try to open the device itself
97  int fd = ::open(dev.toLocal8Bit(), O_RDONLY | O_NONBLOCK);
98  if (fd < 0) {
99  qWarning("open failed, fd=%d, errno=%d (%s)",
100  fd, errno, strerror(errno));
101 
102  QString reason;
103  switch (errno) {
104  case ENOENT:
105  case ENODEV:
106  case ENXIO:
107  case EIO:
108  reason = QString::number(ENODEV);
109  break;
110  case EBUSY:
111  reason = QString::number(EBUSY);
112  break;
113  default:
114  reason = QString::fromLocal8Bit(strerror(errno));
115  break;
116  }
117  return reason;
118  }
119 
120  // Query OSS driver version
121  m_oss_version = 0x030000;
122 #ifdef OSS_GETVERSION
123  ioctl(fd, OSS_GETVERSION, &m_oss_version);
124 #endif
125  m_fd = fd;
126  return QString();
127 }
128 
129 //***************************************************************************
130 int Kwave::RecordOSS::read(QByteArray &buffer, unsigned int offset)
131 {
132  fd_set rfds;
133  struct timeval tv;
134  int retval;
135  int read_bytes = 0;
136  unsigned int length = buffer.size();
137 
138 // qDebug("RecordOSS::read(), offset=%d, length=%d", offset, length);
139  Q_ASSERT(m_fd >= 0);
140  Q_ASSERT(buffer.size());
141  Q_ASSERT(length);
142  Q_ASSERT(offset < length);
143  if (m_fd < 0) return -EBADF; // file not opened
144  if (buffer.isEmpty()) return -EINVAL; // buffer is null pointer
145  if (!length) return -EINVAL;
146  if (offset >= length) return -EINVAL;
147 
148  length -= offset;
149 
150 #if 0
151  int blocksize = length;
152  int err = ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &blocksize);
153  Q_ASSERT(!err);
154  qDebug("blocksize = %u", blocksize);
155  if (err) {
156  blocksize = length;
157  }
158 
159  blocksize = (127 << 16) + 6;
160  err = ioctl(m_fd, SNDCTL_DSP_SETFRAGMENT, &blocksize);
161 #endif
162 
163  // determine the timeout for reading, use safety factor 2
164  int rate = Kwave::toInt(sampleRate());
165  if (rate < 1) rate = 1;
166 
167  unsigned int timeout = (length / rate) * 2;
168  if (timeout < 2) timeout = 2;
169  quint8 *buf = reinterpret_cast<quint8 *>(buffer.data()) + offset;
170 
171  int mask = 0;
172  retval = ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &mask);
173  Q_ASSERT(!retval);
174  mask = PCM_ENABLE_INPUT;
175  retval = ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &mask);
176  Q_ASSERT(!retval);
177 
178  while (length) {
179  FD_ZERO(&rfds);
180  FD_SET(m_fd, &rfds);
181 
182  tv.tv_sec = timeout;
183  tv.tv_usec = 0;
184  retval = select(m_fd+1, &rfds, Q_NULLPTR, Q_NULLPTR, &tv);
185 
186  if (retval == -1) {
187  if (errno == EINTR)
188  return -errno; // return without warning
189 
190  qWarning("RecordOSS::read() - select() failed errno=%d (%s)",
191  errno, strerror(errno));
192  return -errno;
193  } else if (retval) {
194  ssize_t res = ::read(m_fd, buf, length);
195 
196  if ((res == -1) && (errno == EINTR))
197  return -errno; // interrupted, return without warning
198 
199  if ((res == -1) && (errno == EAGAIN))
200  continue;
201 
202  if (res < 0) {
203  qWarning("RecordOSS::read() - read error %d (%s)",
204  errno, strerror(errno));
205  return read_bytes;
206  }
207  read_bytes += res;
208  length -= res;
209  buf += res;
210  } else {
211  printf("No data within 5 seconds.\n");
212  return -EIO;
213  }
214  }
215 
216  return read_bytes;
217 }
218 
219 //***************************************************************************
221 {
222  if (m_fd < 0) return 0; // already closed
223  ::close(m_fd);
224  m_fd = -1;
225  m_oss_version = -1;
226 
227  return 0;
228 }
229 
230 //***************************************************************************
231 static bool addIfExists(QStringList &list, const QString &name)
232 {
233  QFile file;
234 
235  if (name.contains(_("%1"))) {
236  // test for the name without suffix first
237  addIfExists(list, name.arg(_("")));
238 
239  // loop over the list and try until a suffix does not exist
240  for (unsigned int index=0; index < 64; index++)
241  addIfExists(list, name.arg(index));
242  } else {
243  // check a single name
244  file.setFileName(name);
245  if (!file.exists())
246  return false;
247 
248  if (!list.contains(name))
249  list.append(name);
250  }
251 
252  return true;
253 }
254 
255 //***************************************************************************
256 static void scanFiles(QStringList &list, const QString &dirname,
257  const QString &mask)
258 {
259  QStringList files;
260  QDir dir;
261 
262  dir.setPath(dirname);
263  dir.setNameFilters(mask.split(QLatin1Char(' ')));
264  dir.setFilter(QDir::Files | QDir::Readable | QDir::System);
265  dir.setSorting(QDir::Name);
266  files = dir.entryList();
267 
268  for (QStringList::Iterator it = files.begin(); it != files.end(); ++it) {
269  QString devicename = dirname + QDir::separator() + (*it);
270  addIfExists(list, devicename);
271  }
272 }
273 
274 //***************************************************************************
275 static void scanDirectory(QStringList &list, const QString &dir)
276 {
277  scanFiles(list, dir, _("*audio*"));
278  scanFiles(list, dir, _("adsp*"));
279  scanFiles(list, dir, _("dsp*"));
280  scanFiles(list, dir, _("dio*"));
281  scanFiles(list, dir, _("pcm*"));
282 }
283 
284 //***************************************************************************
286 {
287  QStringList list, dirlist;
288 
289  scanDirectory(list, _("/dev"));
290  scanDirectory(list, _("/dev/sound"));
291  scanFiles(dirlist, _("/dev/oss"), _("[^.]*"));
292  foreach(QString dir, dirlist)
293  scanDirectory(list, dir);
294  list.append(_("#EDIT#"));
295  list.append(_("#SELECT#"));
296 
297  return list;
298 }
299 
300 //***************************************************************************
302 {
303  QString filter;
304 
305  if (filter.length()) filter += _("\n");
306  filter += _("audio*|") + i18n("OSS recording device (audio*)");
307  filter += _("dsp*|") + i18n("OSS recording device (dsp*)");
308 
309  if (filter.length()) filter += _("\n");
310  filter += _("adsp*|") + i18n("ALSA recording device (adsp*)");
311 
312  if (filter.length()) filter += _("\n");
313  filter += _("*|") + i18n("Any device (*)");
314 
315  return filter;
316 }
317 
318 //***************************************************************************
319 int Kwave::RecordOSS::detectTracks(unsigned int &min, unsigned int &max)
320 {
321  Q_ASSERT(m_fd >= 0);
322  unsigned int t;
323  int err = -1;
324 
325  // preset
326  min = 0;
327  max = 0;
328 
329  // find the smalles number of tracks, limit to MAX_CHANNELS
330  for (t = 1; t < MAX_CHANNELS; t++) {
331  int real_tracks = t;
332  err = ioctl(m_fd, SNDCTL_DSP_CHANNELS, &real_tracks);
333  if ((err >= 0) && (real_tracks == Kwave::toInt(t))) {
334  min = real_tracks;
335  break;
336  }
337  }
338  if (t >= MAX_CHANNELS) {
339  // no minimum track number found :-o
340  qWarning("no minimum track number found, err=%d", err);
341  min = 0;
342  max = 0;
343  return err;
344  }
345 
346  // find the highest number of tracks, start from MAX_CHANNELS downwards
347  max = min;
348  for (t = MAX_CHANNELS; t >= min; t--) {
349  int real_tracks = t;
350  err = ioctl(m_fd, SNDCTL_DSP_CHANNELS, &real_tracks);
351  if ((err >= 0) && (real_tracks == Kwave::toInt(t))) {
352  max = real_tracks;
353  break;
354  }
355  }
356  m_tracks = max;
357 
358  qDebug("RecordOSS::detectTracks, min=%u, max=%u", min, max);
359 
360  return (max > 0) ? 0 : -1;
361 }
362 
363 //***************************************************************************
365 {
366  Q_ASSERT(m_fd >= 0);
367 
368  // set the number of tracks in the device (must already be opened)
369  int t = tracks;
370  int err = ioctl(m_fd, SNDCTL_DSP_CHANNELS, &t);
371  if (err < 0) return err;
372 
373  m_tracks = t;
374  // return the number of tracks if succeeded
375  tracks = t;
376 
377  return 0;
378 }
379 
380 //***************************************************************************
382 {
383  return m_tracks;
384 }
385 
386 //***************************************************************************
388 {
389  QList<double> list;
390  Q_ASSERT(m_fd >= 0);
391 
392  static const int known_rates[] = {
393  1000, // (just for testing)
394  2000, // (just for testing)
395  4000, // standard OSS
396  5125, // seen in Harmony driver (HP712, 715/new)
397  5510, // seen in AD1848 driver
398  5512, // seen in ES1370 driver
399  6215, // seen in ES188X driver
400  6615, // seen in Harmony driver (HP712, 715/new)
401  6620, // seen in AD1848 driver
402  7350, // seen in AWACS and Burgundy sound driver
403  8000, // standard OSS
404  8820, // seen in AWACS and Burgundy sound driver
405  9600, // seen in AD1848 driver
406  11025, // soundblaster
407  14700, // seen in AWACS and Burgundy sound driver
408  16000, // standard OSS
409  17640, // seen in AWACS and Burgundy sound driver
410  18900, // seen in Harmony driver (HP712, 715/new)
411  22050, // soundblaster
412  24000, // seen in NM256 driver
413  27428, // seen in Harmony driver (HP712, 715/new)
414  29400, // seen in AWACS and Burgundy sound driver
415  32000, // standard OSS
416  32768, // seen in CS4299 driver
417  33075, // seen in Harmony driver (HP712, 715/new)
418  37800, // seen in Harmony driver (HP712, 715/new)
419  44100, // soundblaster
420  48000, // AC97
421  64000, // AC97
422  88200, // seen in RME96XX driver
423  96000, // AC97
424  128000, // (just for testing)
425  176400, // Envy24ht
426  192000, // AC97
427  196000, // (just for testing)
428  200000, // Lynx2
429  256000 // (just for testing)
430  };
431 
432  // try all known sample rates
433  for (unsigned int i=0; i < sizeof(known_rates)/sizeof(int); i++) {
434  int rate = known_rates[i];
435  int err = ioctl(m_fd, SNDCTL_DSP_SPEED, &rate);
436  if (err < 0) {
437 // qDebug("RecordOSS::detectSampleRates(): "
438 // "sample rate %d Hz not supported", known_rates[i]);
439  continue;
440  }
441 
442  // do not produce duplicates
443  bool is_duplicate = false;
444  foreach (const double &r, list)
445  if (qFuzzyCompare(rate, r)) { is_duplicate = true; break; }
446  if (is_duplicate) continue;
447 
448  // qDebug("found rate %d Hz", rate);
449  list.append(rate);
450  m_rate = rate;
451  }
452 
453  return list;
454 }
455 
456 //***************************************************************************
457 int Kwave::RecordOSS::setSampleRate(double &new_rate)
458 {
459  Q_ASSERT(m_fd >= 0);
460  // OSS supports only integer rates
461  int rate = Kwave::toInt(rint(new_rate));
462 
463  // set the rate of the device (must already be opened)
464  int err = ioctl(m_fd, SNDCTL_DSP_SPEED, &rate);
465  if (err < 0) return err;
466 
467  m_rate = rate;
468  // return the sample rate if succeeded
469  new_rate = static_cast<double>(rate);
470 
471  return 0;
472 }
473 
474 //***************************************************************************
476 {
477  Q_ASSERT(m_fd >= 0);
478 
479  return m_rate;
480 }
481 
482 //***************************************************************************
485  int &bits,
486  Kwave::SampleFormat::Format &sample_format)
487 {
488 
489  switch (format) {
490  case AFMT_MU_LAW:
491  compression = Kwave::Compression::G711_ULAW;
492  sample_format = Kwave::SampleFormat::Signed;
493  bits = 16;
494  break;
495  case AFMT_A_LAW:
496  compression = Kwave::Compression::G711_ALAW;
497  sample_format = Kwave::SampleFormat::Unsigned;
498  bits = 16;
499  break;
500  case AFMT_IMA_ADPCM:
501  compression = Kwave::Compression::MS_ADPCM;
502  sample_format = Kwave::SampleFormat::Signed;
503  bits = 16;
504  break;
505  case AFMT_U8:
506  compression = Kwave::Compression::NONE;
507  sample_format = Kwave::SampleFormat::Unsigned;
508  bits = 8;
509  break;
510  case AFMT_S16_LE: /* FALLTHROUGH */
511  case AFMT_S16_BE:
512  compression = Kwave::Compression::NONE;
513  sample_format = Kwave::SampleFormat::Signed;
514  bits = 16;
515  break;
516  case AFMT_S8:
517  compression = Kwave::Compression::NONE;
518  sample_format = Kwave::SampleFormat::Signed;
519  bits = 8;
520  break;
521  case AFMT_U16_LE: /* FALLTHROUGH */
522  case AFMT_U16_BE:
523  compression = Kwave::Compression::NONE;
524  sample_format = Kwave::SampleFormat::Unsigned;
525  bits = 16;
526  break;
527  case AFMT_MPEG:
528  compression = Kwave::Compression::MPEG_LAYER_II;
529  sample_format = Kwave::SampleFormat::Signed;
530  bits = 16;
531  break;
532 #if 0
533  case AFMT_AC3: /* Dolby Digital AC3 */
534  compression = Kwave::Compression::NONE;
535  sample_format = Kwave::SampleFormat::Unknown;
536  bits = 16;
537  break;
538 #endif
539  case AFMT_S24_LE: /* FALLTHROUGH */
540  case AFMT_S24_BE:
541  compression = Kwave::Compression::NONE;
542  sample_format = Kwave::SampleFormat::Signed;
543  bits = 24;
544  break;
545  case AFMT_S32_LE: /* FALLTHROUGH */
546  case AFMT_S32_BE:
547  compression = Kwave::Compression::NONE;
548  sample_format = Kwave::SampleFormat::Signed;
549  bits = 32;
550  break;
551  default:
552  compression = Kwave::Compression::NONE;
553  sample_format = Kwave::SampleFormat::Unknown;
554  bits = -1;
555  }
556 
557 }
558 
559 //***************************************************************************
561  int bits,
562  Kwave::SampleFormat::Format sample_format)
563 {
564  // first level: compression
565  if (compression == Kwave::Compression::G711_ULAW) return AFMT_MU_LAW;
566  if (compression == Kwave::Compression::G711_ALAW) return AFMT_A_LAW;
567  if (compression == Kwave::Compression::MS_ADPCM) return AFMT_IMA_ADPCM;
568  if (compression == static_cast<int>(Kwave::Compression::MPEG_LAYER_II))
569  return AFMT_MPEG;
570 
571  // non-compressed: switch by sample format
572  if ((sample_format == Kwave::SampleFormat::Unsigned) && (bits == 8))
573  return AFMT_U8;
574  if ((sample_format == Kwave::SampleFormat::Signed) && (bits == 8))
575  return AFMT_S8;
576 
577  // get supported modes, maybe one endianness is not supported
578  int mask = 0;
579  int err = ioctl(m_fd, SNDCTL_DSP_GETFMTS, &mask);
580  if (err < 0) return bits;
581 
582  // unsigned 16 bit mode
583  // note: we prefer the machine's native endianness if both are supported !
584  if ((sample_format == Kwave::SampleFormat::Unsigned) && (bits == 16)) {
585  mask &= (AFMT_U16_LE | AFMT_U16_BE);
586  if (mask != (AFMT_U16_LE | AFMT_U16_BE)) return mask;
587 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
588  return AFMT_U16_BE;
589 #else
590  return AFMT_U16_LE;
591 #endif
592  }
593 
594  // signed 16 bit mode
595  if ((sample_format == Kwave::SampleFormat::Signed) && (bits == 16)) {
596  mask &= (AFMT_S16_LE | AFMT_S16_BE);
597  if (mask != (AFMT_S16_LE | AFMT_S16_BE)) return mask;
598 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
599  return AFMT_S16_BE;
600 #else
601  return AFMT_S16_LE;
602 #endif
603  }
604 
605  if ((sample_format == Kwave::SampleFormat::Signed) && (bits == 24)) {
606  mask &= (AFMT_S24_LE | AFMT_S24_BE);
607  if (mask != (AFMT_S24_LE | AFMT_S24_BE)) return mask;
608 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
609  return AFMT_S24_BE;
610 #else
611  return AFMT_S24_LE;
612 #endif
613  }
614 
615  if ((sample_format == Kwave::SampleFormat::Signed) && (bits == 32)) {
616  mask &= (AFMT_S32_LE | AFMT_S32_BE);
617  if (mask != (AFMT_S32_LE | AFMT_S32_BE)) return mask;
618 #if Q_BYTE_ORDER == Q_BIG_ENDIAN
619  return AFMT_S32_BE;
620 #else
621  return AFMT_S32_LE;
622 #endif
623  }
624 
625  qWarning("RecordOSS: unknown format: sample_format=%d, bits=%d",
626  static_cast<int>(sample_format), bits);
627  return 0;
628 }
629 
630 //***************************************************************************
631 QList<Kwave::Compression::Type> Kwave::RecordOSS::detectCompressions()
632 {
633  Q_ASSERT(m_fd >= 0);
634  QList<Kwave::Compression::Type> compressions;
635  int err = 0;
636  int mask = AFMT_QUERY;
637 
638  err = ioctl(m_fd, SNDCTL_DSP_GETFMTS, &mask);
639  if (err < 0) return compressions;
640 
641  if (mask & AFMT_MPEG) compressions += Kwave::Compression::MPEG_LAYER_II;
642  if (mask & AFMT_A_LAW) compressions += Kwave::Compression::G711_ALAW;
643  if (mask & AFMT_MU_LAW) compressions += Kwave::Compression::G711_ULAW;
644  if (mask & AFMT_IMA_ADPCM) compressions += Kwave::Compression::MS_ADPCM;
645  if (mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_S16_LE | AFMT_S16_BE |
647  AFMT_S8 | AFMT_U8))
648  compressions += Kwave::Compression::NONE;
649 
650  return compressions;
651 }
652 
653 //***************************************************************************
655 {
656  Q_ASSERT(m_fd >= 0);
658  int bits, format = AFMT_QUERY;
659  Kwave::SampleFormat::Format sample_format;
660 
661  // read back current format
662  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &format);
663  if (err < 0) return -1;
664  format2mode(format, compression, bits, sample_format);
665 
666  // modify the compression
667  compression = new_compression;
668 
669  // activate new format
670  format = mode2format(compression, bits, sample_format);
671  err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &format);
672  if (err < 0) return -1;
673 
674  return 0;
675 }
676 
677 //***************************************************************************
679 {
680  Q_ASSERT(m_fd >= 0);
681  int mask = AFMT_QUERY;
682  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &mask);
683  if (err < 0) return Kwave::Compression::NONE;
684 
686  int b;
688  format2mode(mask, c, b, s);
689  return c;
690 }
691 
692 //***************************************************************************
693 QList<unsigned int> Kwave::RecordOSS::supportedBits()
694 {
695  Q_ASSERT(m_fd >= 0);
696  QList<unsigned int> bits;
697  bits.clear();
698  int err = 0;
699  int mask = AFMT_QUERY;
700 
701  err = ioctl(m_fd, SNDCTL_DSP_GETFMTS, &mask);
702  if (err < 0) return bits;
703 
704  // mask out all modes that do not match the current compression
705  const int compression = this->compression();
706  for (unsigned int bit=0; bit < (sizeof(mask) << 3); bit++) {
707  if (!(mask & (1 << bit))) continue;
708 
709  // format is supported, split into compression, bits, sample format
711  int b;
713  format2mode(1 << bit, c, b, s);
714  if (b < 0) continue; // unknown -> skip
715 
716  // take the mode if compression matches and it is not already known
717  if ((c == compression) && !(bits.contains(b))) {
718  bits += b;
719  }
720  }
721 
722 #if 0
723  if (mask | AFMT_AC3)
724  qDebug("RecordOSS: your device supports AC3 which is not "\
725  "yet supported, sorry :-(");
726 #endif
727  return bits;
728 }
729 
730 //***************************************************************************
731 int Kwave::RecordOSS::setBitsPerSample(unsigned int new_bits)
732 {
733  Q_ASSERT(m_fd >= 0);
735  int bits, format = AFMT_QUERY;
736  Kwave::SampleFormat::Format sample_format;
737 
738  // read back current format
739  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &format);
740  if (err < 0) return err;
741  format2mode(format, compression, bits, sample_format);
742 
743  // modify the bits per sample
744  bits = new_bits;
745 
746  // activate new format
747  int oldformat = format;
748  format = mode2format(compression, bits, sample_format);
749  err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &format);
750  if (err < 0) return err;
751  if (oldformat != format) return -1;
752 
753  return 0;
754 }
755 
756 //***************************************************************************
758 {
759  Q_ASSERT(m_fd >= 0);
760  int mask = AFMT_QUERY;
761  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &mask);
762  if (err < 0) return err;
763 
765  int b;
767  format2mode(mask, c, b, s);
768  return b;
769 }
770 
771 //***************************************************************************
772 QList<Kwave::SampleFormat::Format> Kwave::RecordOSS::detectSampleFormats()
773 {
774  Q_ASSERT(m_fd >= 0);
775  QList<Kwave::SampleFormat::Format> formats;
776  formats.clear();
777  int err = 0;
778  int mask = AFMT_QUERY;
779 
780  err = ioctl(m_fd, SNDCTL_DSP_GETFMTS, &mask);
781  if (err < 0) return formats;
782 
783  // mask out all modes that do not match the current compression
784  // and bits per sample
786  const int bits_per_sample = this->bitsPerSample();
787  for (unsigned int bit = 0; bit < (sizeof(mask) << 3); bit++) {
788  if (!(mask & (1 << bit))) continue;
789 
790  // format is supported, split into compression, bits, sample format
792  int b;
794  format2mode(1 << bit, c, b, s);
795  if (c < 0) continue; // unknown -> skip
796 
797  if ((c == compression) && (b == bits_per_sample)) {
798  // this mode matches -> append it if not already known
799  if (!formats.contains(s)) formats += s;
800  }
801  }
802 
803  return formats;
804 }
805 
806 //***************************************************************************
808 {
809  Q_ASSERT(m_fd >= 0);
811  int bits, format = AFMT_QUERY;
812  Kwave::SampleFormat::Format sample_format;
813 
814  // read back current format
815  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &format);
816  if (err < 0) return err;
817  format2mode(format, compression, bits, sample_format);
818 
819  // modify the sample format
820  sample_format = new_format;
821 
822  // activate new format
823  int oldformat = format;
824  format = mode2format(compression, bits, sample_format);
825  err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &format);
826  if (err < 0) return err;
827  if (oldformat != format) return -1;
828 
829  return 0;
830 }
831 
832 //***************************************************************************
834 {
835  Q_ASSERT(m_fd >= 0);
836  int mask = AFMT_QUERY;
837  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &mask);
838  if (err < 0) return Kwave::SampleFormat::Unknown;
839 
841  int b;
843  format2mode(mask, c, b, s);
844  return s;
845 }
846 
847 //***************************************************************************
849 {
850  Q_ASSERT(m_fd >= 0);
851  int mask = AFMT_QUERY;
852  int err = ioctl(m_fd, SNDCTL_DSP_SETFMT, &mask);
853  if (err < 0) return Kwave::UnknownEndian;
854 
855  if (mask & (AFMT_U16_LE | AFMT_S16_LE | AFMT_S24_LE | AFMT_S32_LE))
856  return Kwave::LittleEndian;
857 
858  if (mask & (AFMT_U16_BE | AFMT_S16_BE | AFMT_S24_BE | AFMT_S32_BE))
859  return Kwave::BigEndian;
860 
861  if (mask & (AFMT_S8 | AFMT_U8))
862  return Kwave::CpuEndian;
863 
864  return Kwave::UnknownEndian;
865 }
866 
867 #endif /* HAVE_OSS_SUPPORT */
868 
869 //***************************************************************************
870 //***************************************************************************
#define AFMT_S24_LE
Definition: Record-OSS.cpp:45
byte_order_t
Definition: ByteOrder.h:25
Definition: App.h:33
virtual QList< unsigned int > supportedBits() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:693
virtual int read(QByteArray &buffer, unsigned int offset) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:130
#define AFMT_S24_BE
Definition: Record-OSS.cpp:48
virtual QString open(const QString &dev) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:90
#define SNDCTL_DSP_SETFMT
Definition: Record-OSS.cpp:70
virtual QList< Kwave::Compression::Type > detectCompressions() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:631
virtual double sampleRate() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:475
virtual Kwave::Compression::Type compression() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:678
#define AFMT_S32_BE
Definition: Record-OSS.cpp:54
#define MAX_CHANNELS
Definition: Record-OSS.cpp:74
virtual Kwave::byte_order_t endianness() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:848
virtual QStringList supportedDevices() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:285
const char name[16]
Definition: memcpy.c:510
static void scanDirectory(QStringList &list, const QString &dir)
Definition: Record-OSS.cpp:275
virtual QList< double > detectSampleRates() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:387
void format2mode(int format, Kwave::Compression::Type &compression, int &bits, Kwave::SampleFormat::Format &sample_format)
Definition: Record-OSS.cpp:483
int mode2format(Kwave::Compression::Type compression, int bits, Kwave::SampleFormat::Format sample_format)
Definition: Record-OSS.cpp:560
virtual Kwave::SampleFormat::Format sampleFormat() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:833
virtual int setSampleFormat(Kwave::SampleFormat::Format new_format) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:807
#define AFMT_S32_LE
Definition: Record-OSS.cpp:51
int toInt(T x)
Definition: Utils.h:127
static void scanFiles(QStringList &list, const QString &dirname, const QString &mask)
Definition: Record-OSS.cpp:256
virtual int bitsPerSample() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:757
#define SNDCTL_DSP_SPEED
Definition: Record-OSS.cpp:58
virtual int close() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:220
static bool addIfExists(QStringList &list, const QString &name)
Definition: Record-OSS.cpp:231
virtual int setSampleRate(double &new_rate) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:457
virtual QString fileFilter() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:301
virtual ~RecordOSS() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:84
#define _(m)
Definition: memcpy.c:66
virtual int setCompression(Kwave::Compression::Type new_compression) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:654
virtual int tracks() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:381
virtual int detectTracks(unsigned int &min, unsigned int &max) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:319
#define SNDCTL_DSP_CHANNELS
Definition: Record-OSS.cpp:62
virtual QList< Kwave::SampleFormat::Format > detectSampleFormats() Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:772
virtual int setBitsPerSample(unsigned int new_bits) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:731
virtual int setTracks(unsigned int &tracks) Q_DECL_OVERRIDE
Definition: Record-OSS.cpp:364