kwave  18.07.70
Kwave::RecordPulseAudio Class Reference

#include <Record-PulseAudio.h>

Inheritance diagram for Kwave::RecordPulseAudio:
Inheritance graph
Collaboration diagram for Kwave::RecordPulseAudio:
Collaboration graph

Classes

struct  source_info_t
 

Public Member Functions

 RecordPulseAudio ()
 
virtual ~RecordPulseAudio () Q_DECL_OVERRIDE
 
virtual QString open (const QString &dev) Q_DECL_OVERRIDE
 
virtual Kwave::byte_order_t endianness () Q_DECL_OVERRIDE
 
virtual Kwave::SampleFormat::Format sampleFormat () Q_DECL_OVERRIDE
 
virtual int setSampleFormat (Kwave::SampleFormat::Format new_format) Q_DECL_OVERRIDE
 
virtual QList< Kwave::SampleFormat::FormatdetectSampleFormats () Q_DECL_OVERRIDE
 
virtual int bitsPerSample () Q_DECL_OVERRIDE
 
virtual int setBitsPerSample (unsigned int new_bits) Q_DECL_OVERRIDE
 
virtual QList< unsigned int > supportedBits () Q_DECL_OVERRIDE
 
virtual Kwave::Compression::Type compression () Q_DECL_OVERRIDE
 
virtual int setCompression (Kwave::Compression::Type new_compression) Q_DECL_OVERRIDE
 
virtual QList< Kwave::Compression::TypedetectCompressions () Q_DECL_OVERRIDE
 
virtual double sampleRate () Q_DECL_OVERRIDE
 
virtual int setSampleRate (double &new_rate) Q_DECL_OVERRIDE
 
virtual QList< double > detectSampleRates () Q_DECL_OVERRIDE
 
virtual int tracks () Q_DECL_OVERRIDE
 
virtual int setTracks (unsigned int &tracks) Q_DECL_OVERRIDE
 
virtual int detectTracks (unsigned int &min, unsigned int &max) Q_DECL_OVERRIDE
 
virtual int close () Q_DECL_OVERRIDE
 
virtual int read (QByteArray &buffer, unsigned int offset) Q_DECL_OVERRIDE
 
virtual QStringList supportedDevices () Q_DECL_OVERRIDE
 
int mainloopPoll (struct pollfd *ufds, unsigned long int nfds, int timeout)
 
- Public Member Functions inherited from Kwave::RecordDevice
 RecordDevice ()
 
virtual ~RecordDevice ()
 
virtual QString fileFilter ()
 
- Public Member Functions inherited from Kwave::Runnable
virtual ~Runnable ()
 

Protected Member Functions

virtual void run_wrapper (const QVariant &params) Q_DECL_OVERRIDE
 

Private Member Functions

void detectSupportedFormats (const QString &device)
 
void notifySourceInfo (pa_context *c, const pa_source_info *info, int eol)
 
void notifyContext (pa_context *c)
 
void notifyStreamState (pa_stream *stream)
 
void notifyRead (pa_stream *stream, size_t nbytes)
 
bool connectToServer ()
 
void disconnectFromServer ()
 
void scanDevices ()
 
pa_sample_format_t mode2format (int compression, int bits, Kwave::SampleFormat::Format sample_format)
 
int initialize (uint32_t buffer_size)
 

Static Private Member Functions

static void pa_context_notify_cb (pa_context *c, void *userdata)
 
static void pa_source_info_cb (pa_context *c, const pa_source_info *info, int eol, void *userdata)
 
static void pa_stream_state_cb (pa_stream *p, void *userdata)
 
static void pa_read_cb (pa_stream *p, size_t nbytes, void *userdata)
 

Private Attributes

Kwave::WorkerThread m_mainloop_thread
 
QMutex m_mainloop_lock
 
QWaitCondition m_mainloop_signal
 
Kwave::SampleFormat::Format m_sample_format
 
quint8 m_tracks
 
double m_rate
 
Kwave::Compression::Type m_compression
 
unsigned int m_bits_per_sample
 
QList< pa_sample_format_t > m_supported_formats
 
bool m_initialized
 
pa_proplist * m_pa_proplist
 
pa_mainloop * m_pa_mainloop
 
pa_context * m_pa_context
 
pa_stream * m_pa_stream
 
QString m_pa_device
 
QString m_name
 
QString m_device
 
QMap< QString, source_info_tm_device_list
 

Detailed Description

Definition at line 49 of file Record-PulseAudio.h.

Constructor & Destructor Documentation

◆ RecordPulseAudio()

Kwave::RecordPulseAudio::RecordPulseAudio ( )

Constructor

Definition at line 199 of file Record-PulseAudio.cpp.

201  m_mainloop_thread(this, QVariant()),
202  m_mainloop_lock(),
205  m_tracks(0),
206  m_rate(0.0),
210  m_initialized(false),
211  m_pa_proplist(Q_NULLPTR),
212  m_pa_mainloop(Q_NULLPTR),
213  m_pa_context(Q_NULLPTR),
214  m_pa_stream(Q_NULLPTR),
215  m_pa_device(),
216  m_name(i18n("Kwave record")),
217  m_device_list()
218 {
219 }
QList< pa_sample_format_t > m_supported_formats
QWaitCondition m_mainloop_signal
Kwave::WorkerThread m_mainloop_thread
QMap< QString, source_info_t > m_device_list
Kwave::SampleFormat::Format m_sample_format
Kwave::Compression::Type m_compression

◆ ~RecordPulseAudio()

Kwave::RecordPulseAudio::~RecordPulseAudio ( )
virtual

Destructor

Definition at line 222 of file Record-PulseAudio.cpp.

References disconnectFromServer(), and m_device_list.

223 {
225  m_device_list.clear();
226 }
QMap< QString, source_info_t > m_device_list
Here is the call graph for this function:

Member Function Documentation

◆ bitsPerSample()

int Kwave::RecordPulseAudio::bitsPerSample ( )
virtual

Returns the current resolution in bits per sample or a negative error code if failed

Implements Kwave::RecordDevice.

Definition at line 455 of file Record-PulseAudio.cpp.

References m_bits_per_sample.

456 {
457  return m_bits_per_sample;
458 }

◆ close()

int Kwave::RecordPulseAudio::close ( )
virtual

Close the device

Implements Kwave::RecordDevice.

Definition at line 639 of file Record-PulseAudio.cpp.

References m_initialized, m_mainloop_lock, m_mainloop_signal, m_pa_stream, and TIMEOUT_DISCONNECT_STREAM.

Referenced by disconnectFromServer(), open(), setBitsPerSample(), setCompression(), setSampleFormat(), setSampleRate(), and setTracks().

640 {
641  if (m_pa_stream) {
642  pa_stream_drop(m_pa_stream);
643 
644  m_mainloop_lock.lock();
645  pa_stream_disconnect(m_pa_stream);
646  qDebug("RecordPulseAudio::close() - waiting for stream disconnect...");
648  m_mainloop_lock.unlock();
649  qDebug("RecordPulseAudio::close() - stream disconnect DONE");
650 
651  pa_stream_unref(m_pa_stream);
652  }
653  m_pa_stream = Q_NULLPTR;
654 
655  // we need to re-initialize the next time
656  m_initialized = false;
657  return 0;
658 }
#define TIMEOUT_DISCONNECT_STREAM
QWaitCondition m_mainloop_signal
Here is the caller graph for this function:

◆ compression()

Kwave::Compression::Type Kwave::RecordPulseAudio::compression ( )
virtual

Returns the current compression type (0==none)

Implements Kwave::RecordDevice.

Definition at line 496 of file Record-PulseAudio.cpp.

References m_compression.

Referenced by detectCompressions().

497 {
498  return m_compression;
499 }
Kwave::Compression::Type m_compression
Here is the caller graph for this function:

◆ connectToServer()

bool Kwave::RecordPulseAudio::connectToServer ( )
private

Try to connect to the PulseAudio server and create a valid context

Definition at line 886 of file Record-PulseAudio.cpp.

References disconnectFromServer(), m_mainloop_lock, m_mainloop_signal, m_mainloop_thread, m_pa_context, m_pa_mainloop, m_pa_proplist, name, pa_context_notify_cb(), poll_func(), Kwave::WorkerThread::start(), TIMEOUT_CONNECT_TO_SERVER, and UTF8.

Referenced by initialize(), and scanDevices().

887 {
888  if (m_pa_context) return true; // already connected
889 
890  // set hourglass cursor, we are waiting...
891  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
892 
893  // create a property list for this application
894  m_pa_proplist = pa_proplist_new();
895  Q_ASSERT(m_pa_proplist);
896 
897  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_LANGUAGE,
898  UTF8(QLocale::system().name()));
899  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_NAME,
900  UTF8(qApp->applicationName()));
901  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_ICON_NAME,
902  "kwave");
903  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_PROCESS_BINARY,
904  "kwave");
905  pa_proplist_setf(m_pa_proplist, PA_PROP_APPLICATION_PROCESS_ID,
906  "%ld", static_cast<long int>(qApp->applicationPid()));
907  KUser user;
908  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_PROCESS_USER,
909  UTF8(user.loginName()));
910  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_VERSION,
911  UTF8(qApp->applicationVersion()));
912 
913  pa_proplist_sets(m_pa_proplist, PA_PROP_MEDIA_ROLE, "production");
914 
915  // ignore SIGPIPE in this context
916 #ifdef HAVE_SIGNAL_H
917  signal(SIGPIPE, SIG_IGN);
918 #endif
919 
920  m_pa_mainloop = pa_mainloop_new();
921  Q_ASSERT(m_pa_mainloop);
922  pa_mainloop_set_poll_func(m_pa_mainloop, poll_func, this);
923 
924  m_pa_context = pa_context_new_with_proplist(
925  pa_mainloop_get_api(m_pa_mainloop),
926  "Kwave",
928  );
929 
930  // set the callback for getting informed about the context state
931  pa_context_set_state_callback(m_pa_context, pa_context_notify_cb, this);
932 
933  // connect to the pulse audio server server
934  bool failed = false;
935  int error = pa_context_connect(
936  m_pa_context, // context
937  Q_NULLPTR, // server
938  static_cast<pa_context_flags_t>(0), // flags
939  Q_NULLPTR // API
940  );
941  if (error < 0)
942  {
943  qWarning("RecordPulseAudio: pa_contect_connect failed (%s)",
944  pa_strerror(pa_context_errno(m_pa_context)));
945  failed = true;
946  }
947 
948  if (!failed) {
949  m_mainloop_lock.lock();
951 
952  // wait until the context state is either connected or failed
953  failed = true;
956  {
957  if (pa_context_get_state(m_pa_context) == PA_CONTEXT_READY) {
958  failed = false;
959  }
960  }
961  m_mainloop_lock.unlock();
962 
963  if (failed) {
964  qWarning("RecordPulseAudio: context FAILED (%s):-(",
965  pa_strerror(pa_context_errno(m_pa_context)));
966  }
967  }
968 
969  // if the connection failed, clean up
970  if (failed) {
972  }
973 
974  QApplication::restoreOverrideCursor();
975 
976  return !failed;
977 }
const char name[16]
Definition: memcpy.c:510
QWaitCondition m_mainloop_signal
#define TIMEOUT_CONNECT_TO_SERVER
Kwave::WorkerThread m_mainloop_thread
static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata)
static void pa_context_notify_cb(pa_context *c, void *userdata)
virtual void start()
#define UTF8(qs)
Definition: String.h:48
Here is the call graph for this function:
Here is the caller graph for this function:

◆ detectCompressions()

QList< Kwave::Compression::Type > Kwave::RecordPulseAudio::detectCompressions ( )
virtual

Gets a list of supported compression types. If no compression is supported, the list might be empty.

Implements Kwave::RecordDevice.

Definition at line 514 of file Record-PulseAudio.cpp.

References compression(), compression_of(), and m_supported_formats.

515 {
516  QList<Kwave::Compression::Type> list;
517 
518  // try all known sample formats
519  foreach (const pa_sample_format_t &fmt, m_supported_formats)
520  {
522 
523  // do not produce duplicates
524  if (list.contains(compression)) continue;
525 
526  Kwave::Compression t(compression);
527  list.append(compression);
528  }
529 
530  return list;
531 }
QList< pa_sample_format_t > m_supported_formats
static Kwave::Compression::Type compression_of(pa_sample_format_t fmt)
virtual Kwave::Compression::Type compression() Q_DECL_OVERRIDE
Here is the call graph for this function:

◆ detectSampleFormats()

QList< Kwave::SampleFormat::Format > Kwave::RecordPulseAudio::detectSampleFormats ( )
virtual

Gets a list of supported sample formats.

Note
this depends on the current setting of the compression!

Implements Kwave::RecordDevice.

Definition at line 430 of file Record-PulseAudio.cpp.

References bits_of(), compression_of(), m_bits_per_sample, m_compression, m_supported_formats, sample_format_of(), and Kwave::toInt().

431 {
432  QList<Kwave::SampleFormat::Format> list;
433 
434  // try all known sample formats
435  foreach (const pa_sample_format_t &fmt, m_supported_formats)
436  {
437  const Kwave::SampleFormat::Format sample_format = sample_format_of(fmt);
438 
439  // only accept bits/sample if compression types
440  // and bits per sample match
441  if (compression_of(fmt) != m_compression) continue;
443  continue;
444 
445  // do not produce duplicates
446  if (list.contains(sample_format)) continue;
447 
448  list.append(sample_format);
449  }
450 
451  return list;
452 }
QList< pa_sample_format_t > m_supported_formats
static Kwave::Compression::Type compression_of(pa_sample_format_t fmt)
int toInt(T x)
Definition: Utils.h:127
static Kwave::SampleFormat::Format sample_format_of(pa_sample_format_t fmt)
static int bits_of(pa_sample_format_t fmt)
Kwave::Compression::Type m_compression
Here is the call graph for this function:

◆ detectSampleRates()

QList< double > Kwave::RecordPulseAudio::detectSampleRates ( )
virtual

get a list of supported sample rates

Implements Kwave::RecordDevice.

Definition at line 550 of file Record-PulseAudio.cpp.

References ELEMENTS_OF, m_device, and m_device_list.

551 {
552  QList<double> list;
553 
554  static const unsigned int known_rates[] = {
555  1,
556  1000, // (just for testing)
557  2000, // (just for testing)
558  4000, // standard OSS
559  5125, // seen in Harmony driver (HP712, 715/new)
560  5510, // seen in AD1848 driver
561  5512, // seen in ES1370 driver
562  6215, // seen in ES188X driver
563  6615, // seen in Harmony driver (HP712, 715/new)
564  6620, // seen in AD1848 driver
565  7350, // seen in AWACS and Burgundy sound driver
566  8000, // standard OSS
567  8820, // seen in AWACS and Burgundy sound driver
568  9600, // seen in AD1848 driver
569  11025, // soundblaster
570  14700, // seen in AWACS and Burgundy sound driver
571  16000, // standard OSS
572  17640, // seen in AWACS and Burgundy sound driver
573  18900, // seen in Harmony driver (HP712, 715/new)
574  22050, // soundblaster
575  24000, // seen in NM256 driver
576  27428, // seen in Harmony driver (HP712, 715/new)
577  29400, // seen in AWACS and Burgundy sound driver
578  32000, // standard OSS
579  32768, // seen in CS4299 driver
580  33075, // seen in Harmony driver (HP712, 715/new)
581  37800, // seen in Harmony driver (HP712, 715/new)
582  44100, // soundblaster
583  48000, // AC97
584  64000, // AC97
585  88200, // seen in RME96XX driver
586  96000, // AC97
587  128000, // (just for testing)
588  192000 // AC97
589  };
590 
591  pa_sample_spec sampleSpec = m_device_list[m_device].m_sample_spec;
592  uint32_t rate = sampleSpec.rate;
593  for (unsigned int i = 0; i < ELEMENTS_OF(known_rates); i++) {
594  if(known_rates[i] <= rate) {
595  list.append(known_rates[i]);
596  }
597  }
598 
599  return list;
600 }
#define ELEMENTS_OF(__array__)
QMap< QString, source_info_t > m_device_list

◆ detectSupportedFormats()

void Kwave::RecordPulseAudio::detectSupportedFormats ( const QString &  device)
private

Walk through the list of all known formats and collect the ones that are supported into "m_supported_formats".

Parameters
devicename of the device

Definition at line 229 of file Record-PulseAudio.cpp.

References _known_formats, bits_of(), compression_of(), Kwave::CpuEndian, DBG, Kwave::TypesMap< IDX, DATA >::description(), ELEMENTS_OF, endian_of(), Kwave::TypesMap< IDX, DATA >::findFromData(), Kwave::LittleEndian, m_device_list, m_supported_formats, Kwave::Compression::name(), and sample_format_of().

Referenced by open().

230 {
231  // start with an empty list
232  m_supported_formats.clear();
233 
234  // lookup in the device list
235  if (!m_device_list.contains(device))
236  return;
237 
238  const pa_sample_spec &sampleSpec = m_device_list[device].m_sample_spec;
239  const pa_sample_format_t &formatSpec = sampleSpec.format;
240 
241  // try all known formats
242  qDebug("--- list of supported formats --- ");
243  for(unsigned int i = 0; i < ELEMENTS_OF(_known_formats); ++i) {
244  const pa_sample_format_t &fmt = _known_formats[i];
245 
246  if (formatSpec < _known_formats[i])
247  continue;
248 
249  // TODO: avoid duplicate entries that differ only in endianness,
250  // prefer our own (native) endianness
251 
254  qDebug("#%2u, %2u bit [%u byte], %s, '%s', '%s'",
255  i,
256  bits_of(fmt),
257  (bits_of(fmt) + 7) >> 3,
258  endian_of(fmt) == Kwave::CpuEndian ? "CPU" :
259  (endian_of(fmt) == Kwave::LittleEndian ? "LE " : "BE "),
260  DBG(sf.description(sf.findFromData(sample_format_of(fmt)), true)),
261  DBG(t.name())
262  );
263 
264  m_supported_formats.append(fmt);
265  }
266  qDebug("--------------------------------- ");
267 }
QList< pa_sample_format_t > m_supported_formats
static const pa_sample_format_t _known_formats[]
QString description(IDX type, bool localized) const
Definition: TypesMap.h:128
#define ELEMENTS_OF(__array__)
static Kwave::Compression::Type compression_of(pa_sample_format_t fmt)
static Kwave::byte_order_t endian_of(pa_sample_format_t fmt)
QMap< QString, source_info_t > m_device_list
static Kwave::SampleFormat::Format sample_format_of(pa_sample_format_t fmt)
#define DBG(qs)
Definition: String.h:55
static int bits_of(pa_sample_format_t fmt)
IDX findFromData(const DATA &data) const
Definition: TypesMap.h:89
Here is the call graph for this function:
Here is the caller graph for this function:

◆ detectTracks()

int Kwave::RecordPulseAudio::detectTracks ( unsigned int &  min,
unsigned int &  max 
)
virtual

Detect the minimum and maximum number of tracks. If the detection fails, minimum and maximum are set to zero.

Parameters
minreceives the lowest supported number of tracks
maxreceives the highest supported number of tracks
Returns
zero or positive number if ok, negative error number if failed

Implements Kwave::RecordDevice.

Definition at line 628 of file Record-PulseAudio.cpp.

References m_device, and m_device_list.

629 {
630  pa_sample_spec sampleSpec = m_device_list[m_device].m_sample_spec;
631  unsigned int channels = sampleSpec.channels;
632 
633  min = 1;
634  max = qBound<unsigned int>(min, channels, PA_CHANNELS_MAX);
635  return 0;
636 }
QMap< QString, source_info_t > m_device_list

◆ disconnectFromServer()

void Kwave::RecordPulseAudio::disconnectFromServer ( )
private

Disconnect from the PulseAudio server and clean up

Definition at line 980 of file Record-PulseAudio.cpp.

References Kwave::WorkerThread::cancel(), close(), m_mainloop_lock, m_mainloop_thread, m_pa_context, m_pa_mainloop, m_pa_proplist, and Kwave::WorkerThread::stop().

Referenced by connectToServer(), and ~RecordPulseAudio().

981 {
982  close();
983 
984  // stop the main loop
986  if (m_pa_mainloop) {
987  m_mainloop_lock.lock();
988  pa_mainloop_quit(m_pa_mainloop, 0);
989  m_mainloop_lock.unlock();
990  }
992 
993  // disconnect the pulse context
994  if (m_pa_context) {
995  pa_context_disconnect(m_pa_context);
996  pa_context_unref(m_pa_context);
997  m_pa_context = Q_NULLPTR;
998  }
999 
1000  // stop and free the main loop
1001  if (m_pa_mainloop) {
1002  pa_mainloop_free(m_pa_mainloop);
1003  m_pa_mainloop = Q_NULLPTR;
1004  }
1005 
1006  // release the property list
1007  if (m_pa_proplist) {
1008  pa_proplist_free(m_pa_proplist);
1009  m_pa_proplist = Q_NULLPTR;
1010  }
1011 
1012 }
Kwave::WorkerThread m_mainloop_thread
virtual void cancel()
virtual int close() Q_DECL_OVERRIDE
virtual int stop(unsigned int timeout=10000)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ endianness()

Kwave::byte_order_t Kwave::RecordPulseAudio::endianness ( )
virtual

Returns the current endianness (big/little)

Implements Kwave::RecordDevice.

Definition at line 404 of file Record-PulseAudio.cpp.

References endian_of(), m_bits_per_sample, m_compression, m_sample_format, mode2format(), and Kwave::UnknownEndian.

405 {
406  pa_sample_format_t fmt = mode2format(m_compression, m_bits_per_sample,
408  return (fmt != PA_SAMPLE_INVALID) ?
409  endian_of(fmt) : Kwave::UnknownEndian;
410 }
pa_sample_format_t mode2format(int compression, int bits, Kwave::SampleFormat::Format sample_format)
Definition: App.h:33
static Kwave::byte_order_t endian_of(pa_sample_format_t fmt)
Kwave::SampleFormat::Format m_sample_format
Kwave::Compression::Type m_compression
Here is the call graph for this function:

◆ initialize()

int Kwave::RecordPulseAudio::initialize ( uint32_t  buffer_size)
private

Initialize the PulseAudio device with current parameters and prepare it for recording.

Parameters
buffer_sizebuffer size
Returns
zero on success or negative error code -EINVAL or -EIO

Definition at line 713 of file Record-PulseAudio.cpp.

References connectToServer(), DBG, Kwave::TypesMap< IDX, DATA >::description(), Kwave::TypesMap< IDX, DATA >::findFromData(), m_bits_per_sample, m_compression, m_initialized, m_mainloop_lock, m_mainloop_signal, m_name, m_pa_context, m_pa_device, m_pa_stream, m_rate, m_sample_format, m_tracks, mode2format(), name, pa_read_cb(), pa_stream_state_cb(), and TIMEOUT_CONNECT_RECORD.

Referenced by read().

714 {
715  Q_ASSERT(!m_initialized);
716 
717  // make sure that we are connected to the sound server
718  if (!connectToServer()) {
719  qWarning("Connecting to the PulseAudio server failed!");
720  return -1;
721  }
722 
723  pa_sample_format_t fmt = mode2format(m_compression, m_bits_per_sample,
725  if (fmt == PA_SAMPLE_INVALID) {
727 
728  qWarning("format: no matching format for compression '%s', "
729  "%d bits/sample, format '%s'",
733  );
734  return -EINVAL;
735  }
736 
737  pa_sample_spec sample_spec;
738  sample_spec.channels = m_tracks;
739  sample_spec.format = fmt;
740  sample_spec.rate = static_cast<quint32>(m_rate);
741 
742  if(!pa_sample_spec_valid(&sample_spec)) {
744 
745  qWarning("no valid pulse audio format: %d, rate: %0.3g, channels: %d",
746  static_cast<int>(fmt), m_rate, m_tracks);
747  return -EINVAL;
748  }
749 
750  // run with mainloop locked from here on...
751  m_mainloop_lock.lock();
752 
753  pa_channel_map channel_map;
754  pa_channel_map_init_extend(&channel_map, sample_spec.channels,
755  PA_CHANNEL_MAP_DEFAULT);
756 
757  if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
758  qWarning("Channel map doesn't match sample specification!");
759  }
760 
761  // create a new stream
762  m_pa_stream = pa_stream_new(
763  m_pa_context,
764  m_name.toUtf8().constData(),
765  &sample_spec,
766  &channel_map);
767 
768  if (!m_pa_stream) {
769  m_mainloop_lock.unlock();
770  qWarning("Failed to create a PulseAudio stream %s",
771  pa_strerror(pa_context_errno(m_pa_context)));
772  return -1;
773  }
774 
775  pa_stream_set_state_callback(m_pa_stream, pa_stream_state_cb, this);
776  pa_stream_set_read_callback(m_pa_stream, pa_read_cb, this);
777 
778  pa_buffer_attr attr;
779  attr.fragsize = buffer_size;
780  attr.maxlength = static_cast<uint32_t>(-1);
781  attr.minreq = static_cast<uint32_t>(-1);
782  attr.prebuf = static_cast<uint32_t>(-1);
783  attr.tlength = static_cast<uint32_t>(-1);
784  int flags = PA_STREAM_ADJUST_LATENCY;
785 
786  // connect the stream in record mode
787  int result = pa_stream_connect_record(
788  m_pa_stream,
789  m_pa_device.toUtf8().constData(),
790  &attr,
791  static_cast<pa_stream_flags_t>(flags));
792 
793  if (result >= 0) {
795  if (pa_stream_get_state(m_pa_stream) != PA_STREAM_READY)
796  result = -1;
797  }
798 
799  m_mainloop_lock.unlock();
800 
801  if (result < 0) {
802  pa_stream_unref(m_pa_stream);
803  m_pa_stream = Q_NULLPTR;
804  qWarning("Failed to open a PulseAudio stream for record %s",
805  pa_strerror(pa_context_errno(m_pa_context)));
806  return -1;
807  }
808 
809  m_initialized = true;
810  return 0;
811 }
pa_sample_format_t mode2format(int compression, int bits, Kwave::SampleFormat::Format sample_format)
QString description(IDX type, bool localized) const
Definition: TypesMap.h:128
const char name[16]
Definition: memcpy.c:510
QWaitCondition m_mainloop_signal
#define TIMEOUT_CONNECT_RECORD
#define DBG(qs)
Definition: String.h:55
static void pa_read_cb(pa_stream *p, size_t nbytes, void *userdata)
static void pa_stream_state_cb(pa_stream *p, void *userdata)
Kwave::SampleFormat::Format m_sample_format
IDX findFromData(const DATA &data) const
Definition: TypesMap.h:89
Kwave::Compression::Type m_compression
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mainloopPoll()

int Kwave::RecordPulseAudio::mainloopPoll ( struct pollfd *  ufds,
unsigned long int  nfds,
int  timeout 
)

our own poll function, for timeout support

Definition at line 874 of file Record-PulseAudio.cpp.

References m_mainloop_lock.

Referenced by poll_func().

877 {
878  m_mainloop_lock.unlock();
879  int retval = poll(ufds, nfds, timeout);
880  m_mainloop_lock.lock();
881 
882  return retval;
883 }
Here is the caller graph for this function:

◆ mode2format()

pa_sample_format_t Kwave::RecordPulseAudio::mode2format ( int  compression,
int  bits,
Kwave::SampleFormat::Format  sample_format 
)
private

create a PulseAudio device format (enum) from parameters.

Parameters
compressionthe compression type
See also
Compression
Parameters
bitsthe number of bits per sample, related to the decoded stream
sample_formatthe sample format (signed or unsigned)
Returns
the best matching format within the list of known formats, or PA_SAMPLE_INVALID if no match was found

Definition at line 381 of file Record-PulseAudio.cpp.

References bits_of(), compression_of(), m_supported_formats, and sample_format_of().

Referenced by endianness(), and initialize().

383 {
384  // loop over all supported formats and keep only those that are
385  // compatible with the given compression, bits and sample format
386  foreach (const pa_sample_format_t &fmt, m_supported_formats)
387  {
388  if (compression_of(fmt) != compression) continue;
389  if (bits_of(fmt) != bits) continue;
390  if (!(sample_format_of(fmt) == sample_format)) continue;
391 
392  // mode is compatible
393  // As the list of known formats is already sorted so that
394  // the simplest formats come first, we don't have a lot
395  // of work -> just take the first entry ;-)
396  return fmt;
397  }
398 
399  qWarning("RecordPulesAudio::mode2format -> no match found !?");
400  return PA_SAMPLE_INVALID;
401 }
QList< pa_sample_format_t > m_supported_formats
static Kwave::Compression::Type compression_of(pa_sample_format_t fmt)
virtual Kwave::Compression::Type compression() Q_DECL_OVERRIDE
static Kwave::SampleFormat::Format sample_format_of(pa_sample_format_t fmt)
static int bits_of(pa_sample_format_t fmt)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ notifyContext()

void Kwave::RecordPulseAudio::notifyContext ( pa_context *  c)
private

Callback for pulse audio context state changes

Parameters
cpulse server context

Definition at line 345 of file Record-PulseAudio.cpp.

References DBG_CASE, m_mainloop_signal, and m_pa_context.

Referenced by pa_context_notify_cb().

346 {
347  Q_ASSERT(c == m_pa_context);
348  const pa_context_state_t state = pa_context_get_state(c);
349 
350 #ifdef DEBUG
351  #define DBG_CASE(x) case x: qDebug("RecordPulseAudio -> " #x ); break
352  switch (state)
353  {
354  DBG_CASE(PA_CONTEXT_UNCONNECTED);
355  DBG_CASE(PA_CONTEXT_CONNECTING);
356  DBG_CASE(PA_CONTEXT_AUTHORIZING);
357  DBG_CASE(PA_CONTEXT_SETTING_NAME);
358  DBG_CASE(PA_CONTEXT_READY);
359  DBG_CASE(PA_CONTEXT_TERMINATED);
360  DBG_CASE(PA_CONTEXT_FAILED);
361  }
362  #undef DBG_CASE
363 #endif /* DEBUG */
364 
365  switch (state)
366  {
367  case PA_CONTEXT_UNCONNECTED: /* FALLTHROUGH */
368  case PA_CONTEXT_CONNECTING: /* FALLTHROUGH */
369  case PA_CONTEXT_AUTHORIZING: /* FALLTHROUGH */
370  case PA_CONTEXT_SETTING_NAME:
371  break;
372  case PA_CONTEXT_READY: /* FALLTHROUGH */
373  case PA_CONTEXT_TERMINATED: /* FALLTHROUGH */
374  case PA_CONTEXT_FAILED:
375  m_mainloop_signal.wakeAll();
376  break;
377  }
378 }
QWaitCondition m_mainloop_signal
#define DBG_CASE(x)
Here is the caller graph for this function:

◆ notifyRead()

void Kwave::RecordPulseAudio::notifyRead ( pa_stream *  stream,
size_t  nbytes 
)
private

Callback after reading data.

Parameters
streampulse audio stream
nbytesnumber of read bytes, maybe (unused)

Definition at line 280 of file Record-PulseAudio.cpp.

References m_mainloop_signal, and m_pa_stream.

Referenced by pa_read_cb().

281 {
282  Q_UNUSED(nbytes);
283  Q_ASSERT(stream);
284 
285  if (!stream || (stream != m_pa_stream)) return;
286 
287  m_mainloop_signal.wakeAll();
288 }
QWaitCondition m_mainloop_signal
Here is the caller graph for this function:

◆ notifySourceInfo()

void Kwave::RecordPulseAudio::notifySourceInfo ( pa_context *  c,
const pa_source_info *  info,
int  eol 
)
private

Callback for pulse sink info.

Parameters
cpulse server context
infopointer to a source info object
eolif negative: error occurred, zero: more data follows, positive: end of info, done.

Definition at line 1026 of file Record-PulseAudio.cpp.

References Kwave::RecordPulseAudio::source_info_t::m_card, Kwave::RecordPulseAudio::source_info_t::m_description, m_device_list, Kwave::RecordPulseAudio::source_info_t::m_driver, m_mainloop_signal, Kwave::RecordPulseAudio::source_info_t::m_name, m_pa_context, Kwave::RecordPulseAudio::source_info_t::m_sample_spec, and name.

Referenced by pa_source_info_cb().

1029 {
1030  Q_UNUSED(c);
1031  Q_ASSERT(c == m_pa_context);
1032 
1033  if (eol == 0) {
1034  source_info_t i;
1035  i.m_name = QString::fromUtf8(info->name);
1036  i.m_description = QString::fromUtf8(info->description);
1037  i.m_driver = QString::fromUtf8(info->driver);
1038  i.m_card = info->card;
1039  i.m_sample_spec = info->sample_spec;
1040 
1041  QString name = QString::number(m_device_list.count());
1042  m_device_list[name] = i;
1043  } else {
1044  m_mainloop_signal.wakeAll();
1045  }
1046 }
const char name[16]
Definition: memcpy.c:510
QWaitCondition m_mainloop_signal
QMap< QString, source_info_t > m_device_list
Here is the caller graph for this function:

◆ notifyStreamState()

void Kwave::RecordPulseAudio::notifyStreamState ( pa_stream *  stream)
private

Callback for pulse stream state changes

Parameters
streampulse audio stream

Definition at line 300 of file Record-PulseAudio.cpp.

References DBG_CASE, m_mainloop_signal, and m_pa_stream.

Referenced by pa_stream_state_cb().

301 {
302  Q_ASSERT(stream);
303  if (!stream || (stream != m_pa_stream)) return;
304 
305  pa_stream_state_t state = pa_stream_get_state(stream);
306 
307 #ifdef DEBUG
308  #define DBG_CASE(x) case x: qDebug("RecordPulseAudio -> " #x ); break
309  switch (state)
310  {
311  DBG_CASE(PA_STREAM_CREATING);
312  DBG_CASE(PA_STREAM_UNCONNECTED);
313  DBG_CASE(PA_STREAM_FAILED);
314  DBG_CASE(PA_STREAM_TERMINATED);
315  DBG_CASE(PA_STREAM_READY);
316  }
317  #undef DBG_CASE
318 #endif /* DEBUG */
319 
320  switch (state) {
321  case PA_STREAM_CREATING:
322  break;
323  case PA_STREAM_UNCONNECTED: /* FALLTHROUGH */
324  case PA_STREAM_FAILED: /* FALLTHROUGH */
325  case PA_STREAM_TERMINATED: /* FALLTHROUGH */
326  case PA_STREAM_READY:
327  m_mainloop_signal.wakeAll();
328  break;
329  default:
330  Q_ASSERT(0 && "?");
331  break;
332  }
333 }
QWaitCondition m_mainloop_signal
#define DBG_CASE(x)
Here is the caller graph for this function:

◆ open()

QString Kwave::RecordPulseAudio::open ( const QString &  dev)
virtual

Open the record device.

Parameters
devpath of the record device
Return values
QString()if successful
QString::number(ENODEV)if device not found
QString::number(EBUSY)if device is busy
QString(...)device specific error message (already translated)

Implements Kwave::RecordDevice.

Definition at line 814 of file Record-PulseAudio.cpp.

References close(), detectSupportedFormats(), m_device, m_device_list, m_name, m_pa_device, and m_pa_stream.

815 {
816  // close the previous device
817  if (m_pa_stream) close();
818 
819  QString pa_device;
820  if (m_device_list.contains(device))
821  pa_device = m_device_list[device].m_name;
822 
823  if (!pa_device.length())
824  return QString::number(ENODEV);
825 
826  m_pa_device = pa_device;
827  m_device = device;
828 
829  // detect all formats the device knows
830  detectSupportedFormats(device);
831 
832  return QString();
833 }
void detectSupportedFormats(const QString &device)
virtual int close() Q_DECL_OVERRIDE
QMap< QString, source_info_t > m_device_list
Here is the call graph for this function:

◆ pa_context_notify_cb()

void Kwave::RecordPulseAudio::pa_context_notify_cb ( pa_context *  c,
void *  userdata 
)
staticprivate

called from pulse audio to inform about state changes of the server context.

Parameters
cpulse server context
userdatauser data, pointer to a RecordPulseAudio object

Definition at line 336 of file Record-PulseAudio.cpp.

References notifyContext().

Referenced by connectToServer().

337 {
338  Kwave::RecordPulseAudio *record_plugin =
339  reinterpret_cast<Kwave::RecordPulseAudio *>(userdata);
340  Q_ASSERT(record_plugin);
341  if (record_plugin) record_plugin->notifyContext(c);
342 }
void notifyContext(pa_context *c)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_read_cb()

void Kwave::RecordPulseAudio::pa_read_cb ( pa_stream *  p,
size_t  nbytes,
void *  userdata 
)
staticprivate

called from pulse audio after data has been read

Parameters
ppulse audio stream
nbytesnumber of read bytes, maybe (unused)
userdatauser data, pointer to a RecordPulseAudio object

Definition at line 270 of file Record-PulseAudio.cpp.

References notifyRead().

Referenced by initialize().

272 {
273  Kwave::RecordPulseAudio *record_plugin =
274  reinterpret_cast<Kwave::RecordPulseAudio *>(userdata);
275  Q_ASSERT(record_plugin);
276  if (record_plugin) record_plugin->notifyRead(p, nbytes);
277 }
void notifyRead(pa_stream *stream, size_t nbytes)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_source_info_cb()

void Kwave::RecordPulseAudio::pa_source_info_cb ( pa_context *  c,
const pa_source_info *  info,
int  eol,
void *  userdata 
)
staticprivate

called from pulse audio to inform about state changes of the server context.

Parameters
cpulse server context
infopointer to a source info object
eolif negative: error occurred, zero: more data follows, positive: end of info, done.
userdatapointer to a RecordPulseAudio object

Definition at line 1015 of file Record-PulseAudio.cpp.

References notifySourceInfo().

Referenced by scanDevices().

1018 {
1019  Kwave::RecordPulseAudio *record_plugin =
1020  reinterpret_cast<Kwave::RecordPulseAudio *>(userdata);
1021  Q_ASSERT(record_plugin);
1022  if (record_plugin) record_plugin->notifySourceInfo(c, info, eol);
1023 }
void notifySourceInfo(pa_context *c, const pa_source_info *info, int eol)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_stream_state_cb()

void Kwave::RecordPulseAudio::pa_stream_state_cb ( pa_stream *  p,
void *  userdata 
)
staticprivate

called from pulse audio to inform about state changes of a stream.

Parameters
ppulse audio stream
userdatauser data, pointer to a RecordPulseAudio object

Definition at line 291 of file Record-PulseAudio.cpp.

References notifyStreamState().

Referenced by initialize().

292 {
293  Kwave::RecordPulseAudio *record_plugin =
294  reinterpret_cast<Kwave::RecordPulseAudio *>(userdata);
295  Q_ASSERT(record_plugin);
296  if (record_plugin) record_plugin->notifyStreamState(p);
297 }
void notifyStreamState(pa_stream *stream)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read()

int Kwave::RecordPulseAudio::read ( QByteArray &  buffer,
unsigned int  offset 
)
virtual

Read the raw audio data from the record device.

Parameters
bufferarray of bytes to receive the audio data might be resized for alignment
offsetoffset in bytes within the buffer
Returns
number of bytes read, zero or negative if failed

Implements Kwave::RecordDevice.

Definition at line 661 of file Record-PulseAudio.cpp.

References initialize(), m_initialized, m_mainloop_lock, m_pa_stream, MEMCPY, Kwave::toInt(), and Kwave::toUint().

662 {
663  if (buffer.isNull() || buffer.isEmpty())
664  return 0; // no buffer, nothing to do
665 
666  unsigned int length = buffer.size();
667 
668  // we configure our device at a late stage, not on the fly like in OSS
669  if (!m_initialized) {
670  int err = initialize(length);
671  if (err < 0) return err;
672  }
673 
674  m_mainloop_lock.lock();
675 
676  size_t freeBytes = length - offset;
677  size_t readableSize = pa_stream_readable_size(m_pa_stream);
678  if (readableSize > freeBytes) {
679  size_t additional_size = readableSize - freeBytes;
680  buffer.resize(static_cast<int>(length + additional_size));
681  }
682 
683  size_t readLength = 0;
684  if (readableSize > 0) {
685  const void *audioBuffer = Q_NULLPTR;
686  pa_stream_peek(m_pa_stream, &audioBuffer, &readLength);
687 
688  if (offset + readLength > Kwave::toUint(buffer.length())) {
689  pa_stream_drop(m_pa_stream);
690  m_mainloop_lock.unlock();
691  return -EIO; // peek returned invalid length
692  }
693 
694  char *data = buffer.data() + offset;
695  if (audioBuffer) {
696  MEMCPY(data, audioBuffer, readLength); // real data
697  } else {
698  memset(data, 0x00, readLength); // there was a gap
699  }
700 
701  pa_stream_drop(m_pa_stream);
702 
703  } else {
704  m_mainloop_lock.unlock();
705  return -EAGAIN;
706  }
707  m_mainloop_lock.unlock();
708 
709  return Kwave::toInt(readLength);
710 }
int toInt(T x)
Definition: Utils.h:127
#define MEMCPY
Definition: memcpy.h:37
int initialize(uint32_t buffer_size)
unsigned int toUint(T x)
Definition: Utils.h:109
Here is the call graph for this function:

◆ run_wrapper()

void Kwave::RecordPulseAudio::run_wrapper ( const QVariant &  params)
protectedvirtual

re-implementation of the threaded mainloop of PulseAudio

Implements Kwave::Runnable.

Definition at line 852 of file Record-PulseAudio.cpp.

References m_mainloop_lock, and m_pa_mainloop.

853 {
854  Q_UNUSED(params);
855  m_mainloop_lock.lock();
856  pa_mainloop_run(m_pa_mainloop, Q_NULLPTR);
857  m_mainloop_lock.unlock();
858  qDebug("RecordPulseAudio::run_wrapper - done.");
859 }

◆ sampleFormat()

Kwave::SampleFormat::Format Kwave::RecordPulseAudio::sampleFormat ( )
virtual

Returns the current sample format (signed/unsigned)

Implements Kwave::RecordDevice.

Definition at line 413 of file Record-PulseAudio.cpp.

References m_sample_format.

414 {
415  return m_sample_format;
416 }
Kwave::SampleFormat::Format m_sample_format

◆ sampleRate()

double Kwave::RecordPulseAudio::sampleRate ( )
virtual

Returns the current sample rate of the device

Implements Kwave::RecordDevice.

Definition at line 534 of file Record-PulseAudio.cpp.

References m_rate.

535 {
536  return m_rate;
537 }

◆ scanDevices()

void Kwave::RecordPulseAudio::scanDevices ( )
private

scan all PulseAudio source, re-creates m_device_list

Definition at line 1049 of file Record-PulseAudio.cpp.

References _, connectToServer(), m_device_list, m_mainloop_lock, m_mainloop_signal, m_pa_context, name, pa_source_info_cb(), and TIMEOUT_WAIT_DEVICE_SCAN.

Referenced by supportedDevices().

1050 {
1051  if (!m_pa_context) connectToServer();
1052  if (!m_pa_context) return;
1053 
1054  // fetch the device list from the PulseAudio server
1055  m_mainloop_lock.lock();
1056  m_device_list.clear();
1057  pa_operation *op_source_info = pa_context_get_source_info_list(
1058  m_pa_context,
1060  this
1061  );
1062  if (op_source_info) {
1063  // set hourglass cursor, we have a long timeout...
1064  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1066  QApplication::restoreOverrideCursor();
1067  }
1068 
1069  // create a list with final names
1070  QMap<QString, source_info_t> list;
1071 
1072  foreach (QString source, m_device_list.keys()) {
1073  QString name = m_device_list[source].m_name;
1074  QString description = m_device_list[source].m_description;
1075  QString driver = m_device_list[source].m_driver;
1076 
1077  // if the name is not unique, add the internal source name
1078  int unique = true;
1079  foreach (QString s, m_device_list.keys()) {
1080  if (s == source) continue;
1081  if ((m_device_list[s].m_description == description) &&
1082  (m_device_list[s].m_driver == driver))
1083  {
1084  unique = false;
1085  break;
1086  }
1087  }
1088  if (!unique) description += _(" [") + name + _("]");
1089 
1090  // mangle the driver name, e.g.
1091  // "module-alsa-sink.c" -> "alsa sink"
1092  QFileInfo f(driver);
1093  driver = f.baseName();
1094  driver.replace(_("-"), _(" "));
1095  driver.replace(_("_"), _(" "));
1096  if (driver.toLower().startsWith(_("module ")))
1097  driver.remove(0, 7);
1098  description.prepend(driver + _("|sound_card||"));
1099 
1100  // add the leaf node
1101  if (m_device_list[source].m_card != PA_INVALID_INDEX)
1102  description.append(_("|sound_device"));
1103  else
1104  description.append(_("|sound_note"));
1105 
1106  list.insert(description, m_device_list[source]);
1107  }
1108 
1109  m_device_list.clear();
1110  m_device_list = list;
1111  m_mainloop_lock.unlock();
1112 }
const char name[16]
Definition: memcpy.c:510
QWaitCondition m_mainloop_signal
static void pa_source_info_cb(pa_context *c, const pa_source_info *info, int eol, void *userdata)
QMap< QString, source_info_t > m_device_list
#define TIMEOUT_WAIT_DEVICE_SCAN
#define _(m)
Definition: memcpy.c:66
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setBitsPerSample()

int Kwave::RecordPulseAudio::setBitsPerSample ( unsigned int  new_bits)
virtual

Set the resolution in bits per sample

Parameters
new_bitsresolution [bits/sample]
Returns
zero on success, negative error code if failed

Implements Kwave::RecordDevice.

Definition at line 461 of file Record-PulseAudio.cpp.

References close(), and m_bits_per_sample.

462 {
463  if (m_bits_per_sample == new_bits)
464  return 0;
465  close();
466  m_bits_per_sample = new_bits;
467  return 0;
468 }
virtual int close() Q_DECL_OVERRIDE
Here is the call graph for this function:

◆ setCompression()

int Kwave::RecordPulseAudio::setCompression ( Kwave::Compression::Type  new_compression)
virtual

Try to set a new compression type.

Parameters
new_compressionthe identifier of the new compression
Returns
zero on success, negative error code if failed
See also
class Compression

Implements Kwave::RecordDevice.

Definition at line 502 of file Record-PulseAudio.cpp.

References close(), and m_compression.

505 {
506  if (m_compression != new_compression) {
507  close();
508  m_compression = new_compression;
509  }
510  return 0;
511 }
virtual int close() Q_DECL_OVERRIDE
Kwave::Compression::Type m_compression
Here is the call graph for this function:

◆ setSampleFormat()

int Kwave::RecordPulseAudio::setSampleFormat ( Kwave::SampleFormat::Format  new_format)
virtual

Try to set a new sample format (signed/unsigned)

Parameters
new_formatthe identifier for the new format
Returns
zero on success, negative error code if failed
See also
class SampleFormat

Implements Kwave::RecordDevice.

Definition at line 419 of file Record-PulseAudio.cpp.

References close(), and m_sample_format.

421 {
422  if (m_sample_format == new_format)
423  return 0;
424  close();
425  m_sample_format = new_format;
426  return 0;
427 }
virtual int close() Q_DECL_OVERRIDE
Kwave::SampleFormat::Format m_sample_format
Here is the call graph for this function:

◆ setSampleRate()

int Kwave::RecordPulseAudio::setSampleRate ( double &  new_rate)
virtual

Try to set a new sample rate.

Parameters
new_ratethe sample rate to be set [samples/second], can be modified and rounded up/down to the nearest supported sample rate if the underlying driver supports that.
Returns
zero on success, negative error code if failed

Implements Kwave::RecordDevice.

Definition at line 540 of file Record-PulseAudio.cpp.

References close(), and m_rate.

541 {
542  if (qFuzzyCompare(new_rate, m_rate))
543  return 0;
544  close();
545  m_rate = new_rate;
546  return 0;
547 }
virtual int close() Q_DECL_OVERRIDE
Here is the call graph for this function:

◆ setTracks()

int Kwave::RecordPulseAudio::setTracks ( unsigned int &  tracks)
virtual

Try to set a new number of tracks.

Note
the device must be open
Parameters
tracksthe number of tracks to be set, can be modified and decreased to the next supported number of tracks if the underlying driver supports that.
Returns
zero on success, negative error code if failed

Implements Kwave::RecordDevice.

Definition at line 609 of file Record-PulseAudio.cpp.

References close(), m_tracks, and tracks().

610 {
611  const quint8 max_tracks = std::numeric_limits<quint8>::max();
612 
613  if (tracks > max_tracks) {
614  tracks = max_tracks;
615  return -1;
616  }
617 
618  if (tracks == m_tracks)
619  return 0;
620 
621  close();
622  m_tracks = static_cast<quint8>(tracks);
623 
624  return 0;
625 }
virtual int close() Q_DECL_OVERRIDE
virtual int tracks() Q_DECL_OVERRIDE
Here is the call graph for this function:

◆ supportedBits()

QList< unsigned int > Kwave::RecordPulseAudio::supportedBits ( )
virtual

Detect a list of supported bits per sample.

Note
this depends on the compression type
Returns
a list of bits per sample, empty if failed

Implements Kwave::RecordDevice.

Definition at line 471 of file Record-PulseAudio.cpp.

References bits_of(), compression_of(), m_compression, and m_supported_formats.

472 {
473  QList<unsigned int> list;
474 
475  // try all known sample formats
476  foreach(const pa_sample_format_t &fmt, m_supported_formats)
477  {
478  const unsigned int bits = bits_of(fmt);
479 
480  // 0 bits means invalid/does not apply
481  if (!bits) continue;
482 
483  // only accept bits/sample if compression matches
484  if (compression_of(fmt) != m_compression) continue;
485 
486  // do not produce duplicates
487  if (list.contains(bits)) continue;
488 
489  list.append(bits);
490  }
491 
492  return list;
493 }
QList< pa_sample_format_t > m_supported_formats
static Kwave::Compression::Type compression_of(pa_sample_format_t fmt)
static int bits_of(pa_sample_format_t fmt)
Kwave::Compression::Type m_compression
Here is the call graph for this function:

◆ supportedDevices()

QStringList Kwave::RecordPulseAudio::supportedDevices ( )
virtual

return a string list with supported device names

Implements Kwave::RecordDevice.

Definition at line 836 of file Record-PulseAudio.cpp.

References _, m_device_list, m_pa_context, m_pa_mainloop, and scanDevices().

837 {
838  QStringList list;
839 
840  // re-validate the list if necessary
841  scanDevices();
842 
843  if (!m_pa_mainloop || !m_pa_context) return list;
844 
845  list = m_device_list.keys();
846  if (!list.isEmpty()) list.prepend(_("#TREE#"));
847 
848  return list;
849 }
QMap< QString, source_info_t > m_device_list
#define _(m)
Definition: memcpy.c:66
Here is the call graph for this function:

◆ tracks()

int Kwave::RecordPulseAudio::tracks ( )
virtual

Returns the current number of tracks

Implements Kwave::RecordDevice.

Definition at line 603 of file Record-PulseAudio.cpp.

References m_tracks.

Referenced by setTracks().

604 {
605  return m_tracks;
606 }
Here is the caller graph for this function:

Member Data Documentation

◆ m_bits_per_sample

unsigned int Kwave::RecordPulseAudio::m_bits_per_sample
private

resolution [bits per sample]

Definition at line 350 of file Record-PulseAudio.h.

Referenced by bitsPerSample(), detectSampleFormats(), endianness(), initialize(), and setBitsPerSample().

◆ m_compression

Kwave::Compression::Type Kwave::RecordPulseAudio::m_compression
private

compression mode

Definition at line 347 of file Record-PulseAudio.h.

Referenced by compression(), detectSampleFormats(), endianness(), initialize(), setCompression(), and supportedBits().

◆ m_device

QString Kwave::RecordPulseAudio::m_device
private

encoded name of the sink

Definition at line 382 of file Record-PulseAudio.h.

Referenced by detectSampleRates(), detectTracks(), and open().

◆ m_device_list

QMap<QString, source_info_t> Kwave::RecordPulseAudio::m_device_list
private

list of available devices key=full encoded name of the sink, data=info about the sink

Definition at line 388 of file Record-PulseAudio.h.

Referenced by detectSampleRates(), detectSupportedFormats(), detectTracks(), notifySourceInfo(), open(), scanDevices(), supportedDevices(), and ~RecordPulseAudio().

◆ m_initialized

bool Kwave::RecordPulseAudio::m_initialized
private

true if initialize() has been successfully been run

Definition at line 361 of file Record-PulseAudio.h.

Referenced by close(), initialize(), and read().

◆ m_mainloop_lock

QMutex Kwave::RecordPulseAudio::m_mainloop_lock
private

lock for the main loop

Definition at line 332 of file Record-PulseAudio.h.

Referenced by close(), connectToServer(), disconnectFromServer(), initialize(), mainloopPoll(), read(), run_wrapper(), and scanDevices().

◆ m_mainloop_signal

QWaitCondition Kwave::RecordPulseAudio::m_mainloop_signal
private

wait condition for mainloopWait/mainloopSignal

Definition at line 335 of file Record-PulseAudio.h.

Referenced by close(), connectToServer(), initialize(), notifyContext(), notifyRead(), notifySourceInfo(), notifyStreamState(), and scanDevices().

◆ m_mainloop_thread

Kwave::WorkerThread Kwave::RecordPulseAudio::m_mainloop_thread
private

worker thread, running the event loop

Definition at line 329 of file Record-PulseAudio.h.

Referenced by connectToServer(), and disconnectFromServer().

◆ m_name

QString Kwave::RecordPulseAudio::m_name
private

record plugin name

Definition at line 379 of file Record-PulseAudio.h.

Referenced by initialize(), and open().

◆ m_pa_context

pa_context* Kwave::RecordPulseAudio::m_pa_context
private

pulse: context of the connection to the server

Definition at line 370 of file Record-PulseAudio.h.

Referenced by connectToServer(), disconnectFromServer(), initialize(), notifyContext(), notifySourceInfo(), scanDevices(), and supportedDevices().

◆ m_pa_device

QString Kwave::RecordPulseAudio::m_pa_device
private

pulse: device

Definition at line 376 of file Record-PulseAudio.h.

Referenced by initialize(), and open().

◆ m_pa_mainloop

pa_mainloop* Kwave::RecordPulseAudio::m_pa_mainloop
private

pulse: main loop

Definition at line 367 of file Record-PulseAudio.h.

Referenced by connectToServer(), disconnectFromServer(), run_wrapper(), and supportedDevices().

◆ m_pa_proplist

pa_proplist* Kwave::RecordPulseAudio::m_pa_proplist
private

pulse: property list of the context

Definition at line 364 of file Record-PulseAudio.h.

Referenced by connectToServer(), and disconnectFromServer().

◆ m_pa_stream

pa_stream* Kwave::RecordPulseAudio::m_pa_stream
private

pulse: playback stream

Definition at line 373 of file Record-PulseAudio.h.

Referenced by close(), initialize(), notifyRead(), notifyStreamState(), open(), and read().

◆ m_rate

double Kwave::RecordPulseAudio::m_rate
private

sample rate

Definition at line 344 of file Record-PulseAudio.h.

Referenced by initialize(), sampleRate(), and setSampleRate().

◆ m_sample_format

Kwave::SampleFormat::Format Kwave::RecordPulseAudio::m_sample_format
private

sample format (signed int, unsigned int, float, ...

Definition at line 338 of file Record-PulseAudio.h.

Referenced by endianness(), initialize(), sampleFormat(), and setSampleFormat().

◆ m_supported_formats

QList<pa_sample_format_t> Kwave::RecordPulseAudio::m_supported_formats
private

list of supported formats of the current device, indices in the global list of known formats. Only valid after a successful call to "open()", otherwise empty

Definition at line 358 of file Record-PulseAudio.h.

Referenced by detectCompressions(), detectSampleFormats(), detectSupportedFormats(), mode2format(), and supportedBits().

◆ m_tracks

quint8 Kwave::RecordPulseAudio::m_tracks
private

number of tracks [0...N-1]

Definition at line 341 of file Record-PulseAudio.h.

Referenced by initialize(), setTracks(), and tracks().


The documentation for this class was generated from the following files: