kwave  18.07.70
Kwave::PlayBackPulseAudio Class Reference

#include <PlayBack-PulseAudio.h>

Inheritance diagram for Kwave::PlayBackPulseAudio:
Inheritance graph
Collaboration diagram for Kwave::PlayBackPulseAudio:
Collaboration graph

Classes

struct  sink_info_t
 

Public Member Functions

 PlayBackPulseAudio (const Kwave::FileInfo &info)
 
virtual ~PlayBackPulseAudio () Q_DECL_OVERRIDE
 
virtual QString open (const QString &device, double rate, unsigned int channels, unsigned int bits, unsigned int bufbase) Q_DECL_OVERRIDE
 
virtual int write (const Kwave::SampleArray &samples) Q_DECL_OVERRIDE
 
virtual int close () Q_DECL_OVERRIDE
 
virtual QStringList supportedDevices () Q_DECL_OVERRIDE
 
virtual QString fileFilter () Q_DECL_OVERRIDE
 
virtual QList< unsigned int > supportedBits (const QString &device) Q_DECL_OVERRIDE
 
virtual int detectChannels (const QString &device, unsigned int &min, unsigned int &max) Q_DECL_OVERRIDE
 
int mainloopPoll (struct pollfd *ufds, unsigned long int nfds, int timeout)
 
- Public Member Functions inherited from Kwave::PlayBackDevice
virtual ~PlayBackDevice ()
 
- Public Member Functions inherited from Kwave::Runnable
virtual ~Runnable ()
 

Protected Member Functions

int flush ()
 
virtual void run_wrapper (const QVariant &params) Q_DECL_OVERRIDE
 

Private Member Functions

void notifyContext (pa_context *c)
 
void notifySinkInfo (pa_context *c, const pa_sink_info *info, int eol)
 
void notifyStreamState (pa_stream *stream)
 
void notifyWrite (pa_stream *stream, size_t nbytes)
 
void notifySuccess (pa_stream *stream, int success)
 
bool connectToServer ()
 
void disconnectFromServer ()
 
void scanDevices ()
 

Static Private Member Functions

static void pa_context_notify_cb (pa_context *c, void *data)
 
static void pa_sink_info_cb (pa_context *c, const pa_sink_info *info, int eol, void *userdata)
 
static void pa_stream_state_cb (pa_stream *p, void *userdata)
 
static void pa_write_cb (pa_stream *p, size_t nbytes, void *userdata)
 
static void pa_stream_success_cb (pa_stream *s, int success, void *userdata)
 

Private Attributes

Kwave::WorkerThread m_mainloop_thread
 
QMutex m_mainloop_lock
 
QWaitCondition m_mainloop_signal
 
Kwave::FileInfo m_info
 
double m_rate
 
unsigned int m_bytes_per_sample
 
void * m_buffer
 
size_t m_buffer_size
 
size_t m_buffer_used
 
unsigned int m_bufbase
 
pa_proplist * m_pa_proplist
 
pa_mainloop * m_pa_mainloop
 
pa_context * m_pa_context
 
pa_stream * m_pa_stream
 
QMap< QString, sink_info_tm_device_list
 

Detailed Description

Definition at line 48 of file PlayBack-PulseAudio.h.

Constructor & Destructor Documentation

◆ PlayBackPulseAudio()

Kwave::PlayBackPulseAudio::PlayBackPulseAudio ( const Kwave::FileInfo info)
explicit

Constructor

Parameters
infothe current FileInfo with metadata

Definition at line 79 of file PlayBack-PulseAudio.cpp.

81  m_mainloop_thread(this, QVariant()),
84  m_info(info),
85  m_rate(0),
87  m_buffer(Q_NULLPTR),
88  m_buffer_size(0),
89  m_buffer_used(0),
90  m_bufbase(10),
91  m_pa_proplist(Q_NULLPTR),
92  m_pa_mainloop(Q_NULLPTR),
93  m_pa_context(Q_NULLPTR),
94  m_pa_stream(Q_NULLPTR),
96 {
97 }
Kwave::WorkerThread m_mainloop_thread
QMap< QString, sink_info_t > m_device_list

◆ ~PlayBackPulseAudio()

Kwave::PlayBackPulseAudio::~PlayBackPulseAudio ( )
virtual

Destructor

Definition at line 100 of file PlayBack-PulseAudio.cpp.

References close().

101 {
102  close();
103 }
virtual int close() Q_DECL_OVERRIDE
Here is the call graph for this function:

Member Function Documentation

◆ close()

int Kwave::PlayBackPulseAudio::close ( )
virtual

Closes the output device.

See also
PlayBackDevice::close

Implements Kwave::PlayBackDevice.

Definition at line 737 of file PlayBack-PulseAudio.cpp.

References disconnectFromServer(), flush(), m_buffer_size, m_buffer_used, m_bytes_per_sample, m_device_list, m_mainloop_lock, m_mainloop_signal, m_pa_context, m_pa_mainloop, m_pa_stream, m_rate, pa_stream_success_cb(), TIMEOUT_MIN_DRAIN, and Kwave::toInt().

Referenced by open(), and ~PlayBackPulseAudio().

738 {
739  // set hourglass cursor, we are waiting...
740  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
741 
742  if (m_buffer_used) flush();
743 
744  if (m_pa_mainloop && m_pa_stream) {
745 
746  pa_operation *op = Q_NULLPTR;
747  m_mainloop_lock.lock();
748  op = pa_stream_drain(m_pa_stream, pa_stream_success_cb, this);
749  Q_ASSERT(op);
750  if (!op) qWarning("pa_stream_drain() failed: '%s'", pa_strerror(
751  pa_context_errno(m_pa_context)));
752 
753  // calculate a reasonable time for the timeout (16 buffers)
754  int samples_per_buffer = Kwave::toInt(
756  );
757  int ms = (!qFuzzyIsNull(m_rate)) ?
758  Kwave::toInt((samples_per_buffer * 1000.0) / m_rate) : 0;
759  int timeout = (ms + 1) * 4;
760  if (timeout < TIMEOUT_MIN_DRAIN)
761  timeout = TIMEOUT_MIN_DRAIN;
762 
763  qDebug("PlayBackPulseAudio::flush(): waiting for drain to finish...");
764  while (op && (pa_operation_get_state(op) != PA_OPERATION_DONE)) {
765  if (!PA_CONTEXT_IS_GOOD(pa_context_get_state(m_pa_context)) ||
766  !PA_STREAM_IS_GOOD(pa_stream_get_state(m_pa_stream))) {
767  qWarning("PlayBackPulseAudio::close(): bad stream state");
768  break;
769  }
770  if (!m_mainloop_signal.wait(&m_mainloop_lock, timeout)) {
771  qWarning("PlayBackPulseAudio::flush(): timed out after %u ms",
772  timeout);
773  break;
774  }
775  }
776  m_mainloop_lock.unlock();
777 
778  if (m_pa_stream) {
779  pa_stream_disconnect(m_pa_stream);
780  pa_stream_unref(m_pa_stream);
781  m_pa_stream = Q_NULLPTR;
782  }
783  }
784 
786  m_device_list.clear();
787 
788  QApplication::restoreOverrideCursor();
789  return 0;
790 }
#define TIMEOUT_MIN_DRAIN
int toInt(T x)
Definition: Utils.h:127
QMap< QString, sink_info_t > m_device_list
static void pa_stream_success_cb(pa_stream *s, int success, void *userdata)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ connectToServer()

bool Kwave::PlayBackPulseAudio::connectToServer ( )
private

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

Definition at line 318 of file PlayBack-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 open(), and scanDevices().

319 {
320  if (m_pa_context) return true; // already connected
321 
322  // set hourglass cursor, we are waiting...
323  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
324 
325  // create a property list for this application
326  m_pa_proplist = pa_proplist_new();
327  Q_ASSERT(m_pa_proplist);
328 
329  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_LANGUAGE,
330  UTF8(QLocale::system().name()));
331  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_NAME,
332  UTF8(qApp->applicationName()));
333  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_ICON_NAME,
334  "kwave");
335  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_PROCESS_BINARY,
336  "kwave");
337  pa_proplist_setf(m_pa_proplist, PA_PROP_APPLICATION_PROCESS_ID,
338  "%ld", static_cast<long int>(qApp->applicationPid()));
339  KUser user;
340  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_PROCESS_USER,
341  UTF8(user.loginName()));
342  pa_proplist_sets(m_pa_proplist, PA_PROP_APPLICATION_VERSION,
343  UTF8(qApp->applicationVersion()));
344 
345  pa_proplist_sets(m_pa_proplist, PA_PROP_MEDIA_ROLE, "production");
346 
347  // ignore SIGPIPE in this context
348 #ifdef HAVE_SIGNAL_H
349  signal(SIGPIPE, SIG_IGN);
350 #endif
351 
352  m_pa_mainloop = pa_mainloop_new();
353  Q_ASSERT(m_pa_mainloop);
354  pa_mainloop_set_poll_func(m_pa_mainloop, poll_func, this);
355 
356  m_pa_context = pa_context_new_with_proplist(
357  pa_mainloop_get_api(m_pa_mainloop),
358  "Kwave",
360  );
361 
362  // set the callback for getting informed about the context state
363  pa_context_set_state_callback(m_pa_context, pa_context_notify_cb, this);
364 
365  // connect to the pulse audio server server
366  bool failed = false;
367  int error = pa_context_connect(
368  m_pa_context, // context
369  Q_NULLPTR, // server
370  static_cast<pa_context_flags_t>(0), // flags
371  Q_NULLPTR // API
372  );
373  if (error < 0)
374  {
375  qWarning("PlayBackPulseAudio: pa_contect_connect failed (%s)",
376  pa_strerror(pa_context_errno(m_pa_context)));
377  failed = true;
378  }
379 
380  if (!failed) {
381  m_mainloop_lock.lock();
383 
384  // wait until the context state is either connected or failed
385  failed = true;
388  {
389  if (pa_context_get_state(m_pa_context) == PA_CONTEXT_READY) {
390  qDebug("PlayBackPulseAudio: context is ready :-)");
391  failed = false;
392  }
393  }
394  m_mainloop_lock.unlock();
395 
396  if (failed) {
397  qWarning("PlayBackPulseAudio: context FAILED (%s):-(",
398  pa_strerror(pa_context_errno(m_pa_context)));
399  }
400  }
401 
402  // if the connection failed, clean up...
403  if (failed) {
405  }
406 
407  QApplication::restoreOverrideCursor();
408 
409  return !failed;
410 }
static void pa_context_notify_cb(pa_context *c, void *data)
Kwave::WorkerThread m_mainloop_thread
const char name[16]
Definition: memcpy.c:510
static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata)
#define TIMEOUT_CONNECT_TO_SERVER
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:

◆ detectChannels()

int Kwave::PlayBackPulseAudio::detectChannels ( const QString &  device,
unsigned int &  min,
unsigned int &  max 
)
virtual

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

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

Reimplemented from Kwave::PlayBackDevice.

Definition at line 915 of file PlayBack-PulseAudio.cpp.

References m_device_list.

918 {
919  min = max = 0;
920 
921  if (m_device_list.isEmpty() || !m_device_list.contains(device))
922  return -1;
923 
924  min = max = m_device_list[device].m_sample_spec.channels;
925  return 0;
926 }
QMap< QString, sink_info_t > m_device_list

◆ disconnectFromServer()

void Kwave::PlayBackPulseAudio::disconnectFromServer ( )
private

Disconnect from the PulseAudio server and clean up

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

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

Referenced by close(), and connectToServer().

414 {
415  // stop the main loop
417  if (m_pa_mainloop) {
418  m_mainloop_lock.lock();
419  pa_mainloop_quit(m_pa_mainloop, 0);
420  m_mainloop_lock.unlock();
421  }
423 
424  // disconnect the pulse context
425  if (m_pa_context) {
426  pa_context_disconnect(m_pa_context);
427  pa_context_unref(m_pa_context);
428  m_pa_context = Q_NULLPTR;
429  }
430 
431  // stop and free the main loop
432  if (m_pa_mainloop) {
433  pa_mainloop_free(m_pa_mainloop);
434  m_pa_mainloop = Q_NULLPTR;
435  qDebug("PlayBackPulseAudio: mainloop freed");
436  }
437 
438  // release the property list
439  if (m_pa_proplist) {
440  pa_proplist_free(m_pa_proplist);
441  m_pa_proplist = Q_NULLPTR;
442  }
443 
444 }
Kwave::WorkerThread m_mainloop_thread
virtual void cancel()
virtual int stop(unsigned int timeout=10000)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ fileFilter()

QString Kwave::PlayBackPulseAudio::fileFilter ( )
virtual

return a string suitable for a "File Open..." dialog

Reimplemented from Kwave::PlayBackDevice.

Definition at line 890 of file PlayBack-PulseAudio.cpp.

References _, and supportedBits().

891 {
892  return _("");
893 }
#define _(m)
Definition: memcpy.c:66
Here is the call graph for this function:

◆ flush()

int Kwave::PlayBackPulseAudio::flush ( )
protected

Writes the output buffer to the device

Definition at line 653 of file PlayBack-PulseAudio.cpp.

References m_buffer, m_buffer_size, m_buffer_used, m_bytes_per_sample, m_mainloop_lock, m_mainloop_signal, m_pa_context, m_pa_mainloop, m_pa_stream, m_rate, TIMEOUT_MIN_FLUSH, and Kwave::toInt().

Referenced by close(), and write().

654 {
656  return 0;
657 // qDebug("PlayBackPulseAudio::flush(): using buffer %p (%u bytes)",
658 // m_buffer, m_buffer_size);
659 
660  // calculate a reasonable time for the timeout (16 buffers)
661  int samples_per_buffer = Kwave::toInt(
663  );
664  int ms = (!qFuzzyIsNull(m_rate)) ?
665  Kwave::toInt((samples_per_buffer * 1000.0) / m_rate) : 0;
666  int timeout = (ms + 1) * 16;
667  if (timeout < TIMEOUT_MIN_FLUSH)
668  timeout = TIMEOUT_MIN_FLUSH;
669 
670  // write out the buffer allocated before in "write"
671  int result = 0;
672 
673  while (m_buffer_used) {
674  size_t len;
675 
676  m_mainloop_lock.lock();
677  while (!(len = pa_stream_writable_size(m_pa_stream))) {
678  if (!PA_CONTEXT_IS_GOOD(pa_context_get_state(m_pa_context)) ||
679  !PA_STREAM_IS_GOOD(pa_stream_get_state(m_pa_stream)) ||
680  (static_cast<ssize_t>(len) == -1) )
681  {
682  qWarning("PlayBackPulseAudio::flush(): bad stream state");
683  result = -1;
684  break;
685  }
686  if (!m_mainloop_signal.wait(&m_mainloop_lock, timeout)) {
687  qWarning("PlayBackPulseAudio::flush(): timed out after %u ms",
688  timeout);
689  result = -1;
690  break;
691  }
692  }
693  m_mainloop_lock.unlock();
694  if (result < 0) break;
695 
696  if (len > m_buffer_used) len = m_buffer_used;
697 
698 // qDebug("PlayBackPulseAudio::flush(): writing %u bytes...", len);
699  m_mainloop_lock.lock();
700  result = pa_stream_write(
701  m_pa_stream,
702  m_buffer,
703  len,
704  Q_NULLPTR,
705  0,
706  PA_SEEK_RELATIVE
707  );
708  m_mainloop_lock.unlock();
709 
710  if (result < 0) {
711  qWarning("PlayBackPulseAudio::flush(): pa_stream_write failed");
712  return -EIO;
713  }
714 
715  m_buffer = reinterpret_cast<quint8 *>(m_buffer) + len;
716  m_buffer_used -= len;
717  }
718 
719 // qDebug("PlayBackPulseAudio::flush(): flush done.");
720 
721  // buffer is written out now
722  m_buffer_used = 0;
723  m_buffer = Q_NULLPTR;
724  return result;
725 }
#define TIMEOUT_MIN_FLUSH
int toInt(T x)
Definition: Utils.h:127
Here is the call graph for this function:
Here is the caller graph for this function:

◆ mainloopPoll()

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

our own poll function, for timeout support

Definition at line 306 of file PlayBack-PulseAudio.cpp.

References m_mainloop_lock.

Referenced by poll_func().

309 {
310  m_mainloop_lock.unlock();
311  int retval = poll(ufds, nfds, timeout);
312  m_mainloop_lock.lock();
313 
314  return retval;
315 }
Here is the caller graph for this function:

◆ notifyContext()

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

Callback for pulse audio context state changes

Parameters
cpulse server context

Definition at line 156 of file PlayBack-PulseAudio.cpp.

References m_mainloop_signal, and m_pa_context.

Referenced by pa_context_notify_cb().

157 {
158  Q_ASSERT(c == m_pa_context);
159  switch (pa_context_get_state(c))
160  {
161  case PA_CONTEXT_UNCONNECTED:
162 // qDebug("PlayBackPulseAudio: PA_CONTEXT_UNCONNECTED!?");
163  break;
164  case PA_CONTEXT_CONNECTING:
165 // qDebug("PlayBackPulseAudio: PA_CONTEXT_CONNECTING...");
166  break;
167  case PA_CONTEXT_AUTHORIZING:
168 // qDebug("PlayBackPulseAudio: PA_CONTEXT_AUTHORIZING...");
169  break;
170  case PA_CONTEXT_SETTING_NAME:
171 // qDebug("PlayBackPulseAudio: PA_CONTEXT_SETTING_NAME...");
172  break;
173  case PA_CONTEXT_READY:
174 // qDebug("PlayBackPulseAudio: PA_CONTEXT_READY.");
175  m_mainloop_signal.wakeAll();
176  break;
177  case PA_CONTEXT_TERMINATED:
178  qWarning("PlayBackPulseAudio: PA_CONTEXT_TERMINATED");
179  m_mainloop_signal.wakeAll();
180  break;
181  case PA_CONTEXT_FAILED:
182  qWarning("PlayBackPulseAudio: PA_CONTEXT_FAILED");
183  m_mainloop_signal.wakeAll();
184  break;
185  }
186 }
Here is the caller graph for this function:

◆ notifySinkInfo()

void Kwave::PlayBackPulseAudio::notifySinkInfo ( pa_context *  c,
const pa_sink_info *  info,
int  eol 
)
private

Callback for pulse sink info

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

Definition at line 189 of file PlayBack-PulseAudio.cpp.

References Kwave::PlayBackPulseAudio::sink_info_t::m_card, Kwave::PlayBackPulseAudio::sink_info_t::m_description, m_device_list, Kwave::PlayBackPulseAudio::sink_info_t::m_driver, m_mainloop_signal, Kwave::PlayBackPulseAudio::sink_info_t::m_name, m_pa_context, Kwave::PlayBackPulseAudio::sink_info_t::m_sample_spec, and name.

Referenced by pa_sink_info_cb().

192 {
193  Q_UNUSED(c);
194  Q_ASSERT(c == m_pa_context);
195  if (eol == 0) {
196 #if 0
197  qDebug("PlayBackPulseAudio: [%d] sink='%s' (%s) driver='%s'"\
198  "card=%d, ports=%d",
199  info->index,
200  info->name,
201  info->description,
202  info->driver,
203  info->card,
204  info->n_ports
205  );
206  for (int p = 0; p < info->n_ports; p++) {
207  qDebug(" [%2d] - '%s' (%s), prio=%d%s",
208  p,
209  info->ports[p]->name,
210  info->ports[p]->description,
211  info->ports[p]->priority,
212  (info->ports[p] == info->active_port) ? " <*>" : ""
213  );
214  }
215 #endif
216  sink_info_t i;
217  i.m_name = QString::fromUtf8(info->name);
218  i.m_description = QString::fromUtf8(info->description);
219  i.m_driver = QString::fromUtf8(info->driver);
220  i.m_card = info->card;
221  i.m_sample_spec = info->sample_spec;
222 
223  QString name = QString::number(m_device_list.count());
224  m_device_list[name] = i;
225 
226  } else {
227  m_mainloop_signal.wakeAll();
228  }
229 }
const char name[16]
Definition: memcpy.c:510
QMap< QString, sink_info_t > m_device_list
Here is the caller graph for this function:

◆ notifyStreamState()

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

Callback for pulse stream state changes

Parameters
streampulse audio stream

Definition at line 232 of file PlayBack-PulseAudio.cpp.

References m_mainloop_signal, and m_pa_stream.

Referenced by pa_stream_state_cb().

233 {
234  Q_ASSERT(stream);
235  if (!stream || (stream != m_pa_stream)) return;
236 
237  pa_stream_state_t state = pa_stream_get_state(stream);
238 // switch (state) {
239 // case PA_STREAM_UNCONNECTED:
240 // qDebug(" -> UNCONNECTED"); break;
241 // case PA_STREAM_CREATING:
242 // qDebug(" -> CREATING"); break;
243 // case PA_STREAM_READY:
244 // qDebug(" -> READY"); break;
245 // case PA_STREAM_FAILED:
246 // qDebug(" -> FAILED"); break;
247 // case PA_STREAM_TERMINATED:
248 // qDebug(" -> TERMINATED"); break;
249 // default:
250 // Q_ASSERT(0 && "?");
251 // qDebug(" -> ???"); break;
252 // }
253  switch (state) {
254  case PA_STREAM_UNCONNECTED:
255  case PA_STREAM_CREATING:
256  break;
257  case PA_STREAM_READY:
258  case PA_STREAM_FAILED:
259  case PA_STREAM_TERMINATED:
260  m_mainloop_signal.wakeAll();
261  break;
262  }
263 }
Here is the caller graph for this function:

◆ notifySuccess()

void Kwave::PlayBackPulseAudio::notifySuccess ( pa_stream *  stream,
int  success 
)
private

Callback after successful stream operations.

Parameters
streampulse audio stream
success(unused)

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

References m_mainloop_signal, and m_pa_stream.

Referenced by pa_stream_success_cb().

281 {
282 // qDebug("PlayBackPulseAudio::notifySuccess(stream=%p, success=%d)",
283 // static_cast<void *>(stream), success);
284  Q_UNUSED(success);
285 
286  Q_ASSERT(stream);
287  Q_ASSERT(stream == m_pa_stream);
288  if (!stream || (stream != m_pa_stream)) return;
289 
290  m_mainloop_signal.wakeAll();
291 }
Here is the caller graph for this function:

◆ notifyWrite()

void Kwave::PlayBackPulseAudio::notifyWrite ( pa_stream *  stream,
size_t  nbytes 
)
private

Callback after writing data.

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

Definition at line 266 of file PlayBack-PulseAudio.cpp.

References m_mainloop_signal, and m_pa_stream.

Referenced by pa_write_cb().

267 {
268 // qDebug("PlayBackPulseAudio::notifyWrite(stream=%p, nbytes=%u)",
269 // static_cast<void *>(stream), nbytes);
270  Q_UNUSED(nbytes);
271 
272  Q_ASSERT(stream);
273  Q_ASSERT(stream == m_pa_stream);
274  if (!stream || (stream != m_pa_stream)) return;
275 
276  m_mainloop_signal.wakeAll();
277 }
Here is the caller graph for this function:

◆ open()

QString Kwave::PlayBackPulseAudio::open ( const QString &  device,
double  rate,
unsigned int  channels,
unsigned int  bits,
unsigned int  bufbase 
)
virtual

Opens the device for playback.

See also
PlayBackDevice::open

Implements Kwave::PlayBackDevice.

Definition at line 447 of file PlayBack-PulseAudio.cpp.

References _, close(), connectToServer(), Kwave::FileInfo::contains(), DBG, Kwave::FileInfo::get(), Kwave::INF_AUTHOR, Kwave::INF_COPYRIGHT, Kwave::INF_FILENAME, Kwave::INF_NAME, Kwave::INF_SOFTWARE, m_bufbase, m_buffer, m_buffer_size, m_bytes_per_sample, m_device_list, m_info, m_mainloop_lock, m_mainloop_signal, m_pa_context, m_pa_proplist, m_pa_stream, m_rate, name, pa_stream_state_cb(), pa_write_cb(), scanDevices(), SET_PROPERTY, and TIMEOUT_CONNECT_PLAYBACK.

451 {
452  #define SET_PROPERTY(__property__,__info__) \
453  if (m_info.contains(__info__)) \
454  pa_proplist_sets(_proplist, __property__, \
455  m_info.get(__info__).toString().toUtf8().data())
456 
457  qDebug("PlayBackPulseAudio::open(device=%s,rate=%0.1f,channels=%u,"\
458  "bits=%u, bufbase=%u)",
459  DBG(device.split(_("|")).at(0)), rate, channels,
460  bits, bufbase);
461 
462  m_rate = rate;
463 
464  if (channels > 255)
465  return i18n("%1 channels are not supported, maximum is 255", channels);
466 
467  // close the previous device
468  if (m_pa_stream) close();
469 
470  // make sure that we are connected to the sound server
471  if (!connectToServer()) {
472  return i18n("Connecting to the PulseAudio server failed.");
473  }
474 
475  if (!m_device_list.contains(device)) scanDevices();
476  if (!m_device_list.contains(device)) {
477  return i18n(
478  "The PulseAudio device '%1' is unknown or no longer connected",
479  device.section(QLatin1Char('|'), 0, 0));
480  }
481  QString pa_device = m_device_list[device].m_name;
482 
483  // determine the buffer size
484  m_bytes_per_sample = sizeof(sample_t) * channels;
485  m_buffer_size = 0;
486  m_buffer = Q_NULLPTR;
487  m_bufbase = bufbase;
488 
489  // build a property list for the stream
490  pa_proplist *_proplist = pa_proplist_copy(m_pa_proplist);
491  Q_ASSERT(_proplist);
492  SET_PROPERTY(PA_PROP_MEDIA_TITLE, Kwave::INF_NAME);
493  SET_PROPERTY(PA_PROP_MEDIA_ARTIST, Kwave::INF_AUTHOR);
494 #ifdef PA_PROP_MEDIA_COPYRIGHT
495  SET_PROPERTY(PA_PROP_MEDIA_COPYRIGHT, Kwave::INF_COPYRIGHT);
496 #endif
497 #ifdef PA_PROP_MEDIA_SOFTWARE
498  SET_PROPERTY(PA_PROP_MEDIA_SOFTWARE, Kwave::INF_SOFTWARE);
499 #endif
500 // SET_PROPERTY(PA_PROP_MEDIA_LANGUAGE, Kwave::INF_...);
501  SET_PROPERTY(PA_PROP_MEDIA_FILENAME, Kwave::INF_FILENAME);
502 // SET_PROPERTY(PA_PROP_MEDIA_ICON_NAME, Kwave::INF_...);
503 
504  // use Kwave's internal sample format as output
505  pa_sample_spec sample_spec;
506 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
507  sample_spec.format = PA_SAMPLE_S24_32BE;
508 #else
509  sample_spec.format = PA_SAMPLE_S24_32LE;
510 #endif
511  sample_spec.channels = static_cast<uint8_t>(channels);
512  sample_spec.rate = static_cast<uint32_t>(m_rate);
513 
514  // use the current title / filename or fixed string as stream name
515  QString name;
516  if (m_info.contains(Kwave::INF_NAME)) // first choice: title
517  name = m_info.get(Kwave::INF_NAME).toString();
518  // fallback: filename
519  if (!name.length() && m_info.contains(Kwave::INF_FILENAME))
520  name = m_info.get(Kwave::INF_FILENAME).toString();
521  if (!name.length()) // last resort: fixed string
522  name = i18n("playback...");
523 
524  // run with mainloop locked from here on...
525  m_mainloop_lock.lock();
526 
527  // create a new stream
528  m_pa_stream = pa_stream_new_with_proplist(
529  m_pa_context,
530  name.toUtf8().data(),
531  &sample_spec,
532  Q_NULLPTR /* const pa_channel_map *map */,
533  _proplist);
534  pa_proplist_free(_proplist);
535 
536  if (!m_pa_stream) {
537  m_mainloop_lock.unlock();
538  return i18n("Failed to create a PulseAudio stream (%1).",
539  QString::fromLocal8Bit(
540  pa_strerror(pa_context_errno(m_pa_context))));
541  }
542  qDebug("PlayBackPulseAudio::open(...) - stream created as %p",
543  static_cast<void *>(m_pa_stream));
544 
545  // register callbacks for changes in stream state and write events
546  pa_stream_set_state_callback(m_pa_stream, pa_stream_state_cb, this);
547  pa_stream_set_write_callback(m_pa_stream, pa_write_cb, this);
548 
549  // set buffer attributes
550  if (m_bufbase < 10) m_bufbase = 10;
551  const int s = ((1 << m_bufbase) * m_bytes_per_sample) / m_bytes_per_sample;
552  pa_buffer_attr attr;
553  attr.fragsize = -1;
554  attr.maxlength = s;
555  attr.minreq = -1;
556  attr.prebuf = -1;
557  attr.tlength = -1;
558 
559  // connect the stream in playback mode
560  int result = pa_stream_connect_playback(
561  m_pa_stream,
562  pa_device.length() ? pa_device.toUtf8().data() : Q_NULLPTR,
563  &attr /* buffer attributes */,
564  static_cast<pa_stream_flags_t>(
565  PA_STREAM_INTERPOLATE_TIMING |
566  PA_STREAM_AUTO_TIMING_UPDATE),
567  Q_NULLPTR /* volume */,
568  Q_NULLPTR /* sync stream */ );
569 
570  if (result >= 0) {
572  if (pa_stream_get_state(m_pa_stream) != PA_STREAM_READY)
573  result = -1;
574  }
575  m_mainloop_lock.unlock();
576 
577  if (result < 0) {
578  pa_stream_unref(m_pa_stream);
579  m_pa_stream = Q_NULLPTR;
580  return i18n("Failed to open a PulseAudio stream for playback (%1).",
581  QString::fromLocal8Bit(
582  pa_strerror(pa_context_errno(m_pa_context))));
583  }
584 
585  return QString();
586 }
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
virtual int close() Q_DECL_OVERRIDE
#define SET_PROPERTY(__property__, __info__)
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
const char name[16]
Definition: memcpy.c:510
#define TIMEOUT_CONNECT_PLAYBACK
static void pa_stream_state_cb(pa_stream *p, void *userdata)
static void pa_write_cb(pa_stream *p, size_t nbytes, void *userdata)
#define _(m)
Definition: memcpy.c:66
#define DBG(qs)
Definition: String.h:55
QMap< QString, sink_info_t > m_device_list
qint32 sample_t
Definition: Sample.h:37
Here is the call graph for this function:

◆ pa_context_notify_cb()

void Kwave::PlayBackPulseAudio::pa_context_notify_cb ( pa_context *  c,
void *  data 
)
staticprivate

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

Parameters
cpulse server context
datauser data, pointer to a PlayBackPulseAudio object

Definition at line 106 of file PlayBack-PulseAudio.cpp.

References notifyContext().

Referenced by connectToServer().

107 {
108  Kwave::PlayBackPulseAudio *playback_plugin =
109  reinterpret_cast<Kwave::PlayBackPulseAudio *>(data);
110  Q_ASSERT(playback_plugin);
111  if (playback_plugin) playback_plugin->notifyContext(c);
112 }
void notifyContext(pa_context *c)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_sink_info_cb()

void Kwave::PlayBackPulseAudio::pa_sink_info_cb ( pa_context *  c,
const pa_sink_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 sink info object
eolif negative: error occurred, zero: more data follows, positive: end of info, done.
userdatapointer to a PlayBackPulseAudio object

Definition at line 115 of file PlayBack-PulseAudio.cpp.

References notifySinkInfo().

Referenced by scanDevices().

118 {
119  Kwave::PlayBackPulseAudio *playback_plugin =
120  reinterpret_cast<Kwave::PlayBackPulseAudio *>(userdata);
121  Q_ASSERT(playback_plugin);
122  if (playback_plugin) playback_plugin->notifySinkInfo(c, info, eol);
123 }
void notifySinkInfo(pa_context *c, const pa_sink_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::PlayBackPulseAudio::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 PlayBackPulseAudio object

Definition at line 126 of file PlayBack-PulseAudio.cpp.

References notifyStreamState().

Referenced by open().

127 {
128  Kwave::PlayBackPulseAudio *playback_plugin =
129  reinterpret_cast<Kwave::PlayBackPulseAudio *>(userdata);
130  Q_ASSERT(playback_plugin);
131  if (playback_plugin) playback_plugin->notifyStreamState(p);
132 }
void notifyStreamState(pa_stream *stream)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_stream_success_cb()

void Kwave::PlayBackPulseAudio::pa_stream_success_cb ( pa_stream *  s,
int  success,
void *  userdata 
)
staticprivate

called from pulse audio after data has been written

Parameters
spulse audio stream
successindicates success (unused)
userdatauser data, pointer to a PlayBackPulseAudio object

Definition at line 145 of file PlayBack-PulseAudio.cpp.

References notifySuccess().

Referenced by close().

148 {
149  Kwave::PlayBackPulseAudio *playback_plugin =
150  reinterpret_cast<Kwave::PlayBackPulseAudio *>(userdata);
151  Q_ASSERT(playback_plugin);
152  if (playback_plugin) playback_plugin->notifySuccess(s, success);
153 }
void notifySuccess(pa_stream *stream, int success)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ pa_write_cb()

void Kwave::PlayBackPulseAudio::pa_write_cb ( pa_stream *  p,
size_t  nbytes,
void *  userdata 
)
staticprivate

called from pulse audio after data has been written

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

Definition at line 135 of file PlayBack-PulseAudio.cpp.

References notifyWrite().

Referenced by open().

137 {
138  Kwave::PlayBackPulseAudio *playback_plugin =
139  reinterpret_cast<Kwave::PlayBackPulseAudio *>(userdata);
140  Q_ASSERT(playback_plugin);
141  if (playback_plugin) playback_plugin->notifyWrite(p, nbytes);
142 }
void notifyWrite(pa_stream *stream, size_t nbytes)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_wrapper()

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

re-implementation of the threaded mainloop of PulseAudio

Implements Kwave::Runnable.

Definition at line 728 of file PlayBack-PulseAudio.cpp.

References m_mainloop_lock, and m_pa_mainloop.

729 {
730  Q_UNUSED(params);
731  m_mainloop_lock.lock();
732  pa_mainloop_run(m_pa_mainloop, Q_NULLPTR);
733  m_mainloop_lock.unlock();
734 }

◆ scanDevices()

void Kwave::PlayBackPulseAudio::scanDevices ( )
private

scan all PulseAudio sinks, re-creates m_device_list

Definition at line 793 of file PlayBack-PulseAudio.cpp.

References _, connectToServer(), Kwave::PlayBackPulseAudio::sink_info_t::m_card, Kwave::PlayBackPulseAudio::sink_info_t::m_description, m_device_list, Kwave::PlayBackPulseAudio::sink_info_t::m_driver, m_mainloop_lock, m_mainloop_signal, Kwave::PlayBackPulseAudio::sink_info_t::m_name, m_pa_context, Kwave::PlayBackPulseAudio::sink_info_t::m_sample_spec, name, pa_sink_info_cb(), and TIMEOUT_WAIT_DEVICE_SCAN.

Referenced by open(), and supportedDevices().

794 {
796  if (!m_pa_context) return;
797 
798  // fetch the device list from the PulseAudio server
799  m_mainloop_lock.lock();
800  m_device_list.clear();
801  pa_operation *op_sink_info = pa_context_get_sink_info_list(
802  m_pa_context,
804  this
805  );
806  if (op_sink_info) {
807  // set hourglass cursor, we have a long timeout...
808  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
810  QApplication::restoreOverrideCursor();
811  }
812 
813  // create a list with final names
814 // qDebug("----------------------------------------");
815  QMap<QString, sink_info_t> list;
816 
817  // first entry == default device
818  sink_info_t i;
819  pa_sample_spec s;
820  s.format = PA_SAMPLE_INVALID;
821  s.rate = 0;
822  s.channels = 0;
823  i.m_name = QString();
824  i.m_description = _("(server default)");
825  i.m_driver = QString();
826  i.m_card = -1;
827  i.m_sample_spec = s;
828  list[i18n("(Use server default)") + _("|sound_note")] = i;
829 
830  foreach (QString sink, m_device_list.keys()) {
831  QString name = m_device_list[sink].m_name;
832  QString description = m_device_list[sink].m_description;
833  QString driver = m_device_list[sink].m_driver;
834 
835  // if the name is not unique, add the internal sink name
836  int unique = true;
837  foreach (QString sn, m_device_list.keys()) {
838  if (sn == sink) continue;
839  if ((m_device_list[sn].m_description == description) &&
840  (m_device_list[sn].m_driver == driver))
841  {
842  unique = false;
843  break;
844  }
845  }
846  if (!unique) description += _(" [") + name + _("]");
847 
848  // mangle the driver name, e.g.
849  // "module-alsa-sink.c" -> "alsa sink"
850  QFileInfo f(driver);
851  driver = f.baseName();
852  driver.replace(_("-"), _(" "));
853  driver.replace(_("_"), _(" "));
854  if (driver.toLower().startsWith(_("module ")))
855  driver.remove(0, 7);
856  description.prepend(driver + _("|sound_card||"));
857 
858  // add the leaf node
859  if (m_device_list[sink].m_card != PA_INVALID_INDEX)
860  description.append(_("|sound_device"));
861  else
862  description.append(_("|sound_note"));
863 
864 // qDebug("supported device: '%s'", DBG(description));
865  list.insert(description, m_device_list[sink]);
866  }
867 // qDebug("----------------------------------------");
868 
869  m_device_list = list;
870  m_mainloop_lock.unlock();
871 }
#define TIMEOUT_WAIT_DEVICE_SCAN
const char name[16]
Definition: memcpy.c:510
static void pa_sink_info_cb(pa_context *c, const pa_sink_info *info, int eol, void *userdata)
#define _(m)
Definition: memcpy.c:66
QMap< QString, sink_info_t > m_device_list
Here is the call graph for this function:
Here is the caller graph for this function:

◆ supportedBits()

QList< unsigned int > Kwave::PlayBackPulseAudio::supportedBits ( const QString &  device)
virtual

returns a list of supported bits per sample resolutions of a given device.

Parameters
devicefilename of the device
Returns
list of supported bits per sample, or empty on errors

Implements Kwave::PlayBackDevice.

Definition at line 897 of file PlayBack-PulseAudio.cpp.

References m_device_list, and Kwave::toUint().

Referenced by fileFilter().

900 {
901  QList<unsigned int> list;
902 
903  if ( m_device_list.isEmpty() || !m_device_list.contains(device) ||
904  !pa_sample_spec_valid(&m_device_list[device].m_sample_spec) )
905  return list;
906 
907  list.append(Kwave::toUint(
908  pa_sample_size(&m_device_list[device].m_sample_spec) * 8)
909  );
910 
911  return list;
912 }
QMap< QString, sink_info_t > m_device_list
unsigned int toUint(T x)
Definition: Utils.h:109
Here is the call graph for this function:
Here is the caller graph for this function:

◆ supportedDevices()

QStringList Kwave::PlayBackPulseAudio::supportedDevices ( )
virtual

return a string list with supported device names

Reimplemented from Kwave::PlayBackDevice.

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

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

875 {
876  QStringList list;
877 
878  // re-validate the list if necessary
879  scanDevices();
880 
881  if (!m_pa_mainloop || !m_pa_context) return list;
882 
883  list = m_device_list.keys();
884  if (!list.isEmpty()) list.prepend(_("#TREE#"));
885 
886  return list;
887 }
#define _(m)
Definition: memcpy.c:66
QMap< QString, sink_info_t > m_device_list
Here is the call graph for this function:

◆ write()

int Kwave::PlayBackPulseAudio::write ( const Kwave::SampleArray samples)
virtual

Writes an array of samples to the output device.

See also
PlayBackDevice::write

Implements Kwave::PlayBackDevice.

Definition at line 589 of file PlayBack-PulseAudio.cpp.

References Kwave::SampleArray::constData(), flush(), m_bufbase, m_buffer, m_buffer_size, m_buffer_used, m_bytes_per_sample, m_mainloop_lock, m_pa_mainloop, m_pa_stream, MEMCPY, and Kwave::toUint().

590 {
591  unsigned int bytes = m_bytes_per_sample;
592 
593  // abort if byte per sample is unknown
594  Q_ASSERT(m_bytes_per_sample);
595  Q_ASSERT(m_pa_mainloop);
597  return -EINVAL;
598 
599  // start with a new/empty buffer from PulseAudio
600  if (!m_buffer) {
601  m_mainloop_lock.lock();
602 
603  // estimate buffer size and round to whole samples
604  size_t size = -1;
606 
607  // get a buffer from PulseAudio
608  int result = pa_stream_begin_write(m_pa_stream, &m_buffer, &size);
609  size /= m_bytes_per_sample;
610  size *= m_bytes_per_sample;
611 
612  // we don't use all of it to reduce latency, use only the
613  // minimum of our configured size and pulse audio's offer
614  if (size < m_buffer_size)
615  m_buffer_size = size;
616 
617  m_mainloop_lock.unlock();
618 
619  if (result < 0) {
620  qWarning("PlayBackPulseAudio: pa_stream_begin_write failed");
621  return -EIO;
622  }
623 
624 // qDebug("PlayBackPulseAudio::write(): got buffer %p, size=%u bytes",
625 // m_buffer, m_buffer_size);
626  }
627 
628  // abort with out-of-memory if failed
629  Q_ASSERT(m_buffer);
630  if (!m_buffer || !m_buffer_size)
631  return -ENOMEM;
632 
633  Q_ASSERT (m_buffer_used + bytes <= m_buffer_size);
634  if (m_buffer_used + bytes > m_buffer_size) {
635  qWarning("PlayBackPulseAudio::write(): buffer overflow ?! (%u/%u)",
638  m_buffer_used = 0;
639  return -EIO;
640  }
641 
642  // copy the samples
643  MEMCPY(reinterpret_cast<quint8 *>(m_buffer) + m_buffer_used,
644  samples.constData(), bytes);
645  m_buffer_used += bytes;
646 
647  // write the buffer if it is full
648  if (m_buffer_used >= m_buffer_size) return flush();
649  return 0;
650 }
#define MEMCPY
Definition: memcpy.h:37
const sample_t * constData() const
Definition: SampleArray.h:54
unsigned int toUint(T x)
Definition: Utils.h:109
Here is the call graph for this function:

Member Data Documentation

◆ m_bufbase

unsigned int Kwave::PlayBackPulseAudio::m_bufbase
private

exponent of the buffer size, buffer size should be (1 << m_bufbase)

Definition at line 276 of file PlayBack-PulseAudio.h.

Referenced by open(), and write().

◆ m_buffer

void* Kwave::PlayBackPulseAudio::m_buffer
private

buffer with raw device data

Definition at line 264 of file PlayBack-PulseAudio.h.

Referenced by flush(), open(), and write().

◆ m_buffer_size

size_t Kwave::PlayBackPulseAudio::m_buffer_size
private

buffer size in bytes

Definition at line 267 of file PlayBack-PulseAudio.h.

Referenced by close(), flush(), open(), and write().

◆ m_buffer_used

size_t Kwave::PlayBackPulseAudio::m_buffer_used
private

number of bytes in the buffer

Definition at line 270 of file PlayBack-PulseAudio.h.

Referenced by close(), flush(), and write().

◆ m_bytes_per_sample

unsigned int Kwave::PlayBackPulseAudio::m_bytes_per_sample
private

number of bytes per sample x nr of channels

Definition at line 261 of file PlayBack-PulseAudio.h.

Referenced by close(), flush(), open(), and write().

◆ m_device_list

QMap<QString, sink_info_t> Kwave::PlayBackPulseAudio::m_device_list
private

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

Definition at line 294 of file PlayBack-PulseAudio.h.

Referenced by close(), detectChannels(), notifySinkInfo(), open(), scanDevices(), supportedBits(), and supportedDevices().

◆ m_info

Kwave::FileInfo Kwave::PlayBackPulseAudio::m_info
private

file info, for meta info like title, author, name etc.

Definition at line 255 of file PlayBack-PulseAudio.h.

Referenced by open().

◆ m_mainloop_lock

QMutex Kwave::PlayBackPulseAudio::m_mainloop_lock
private

lock for the main loop

Definition at line 249 of file PlayBack-PulseAudio.h.

Referenced by close(), connectToServer(), disconnectFromServer(), flush(), mainloopPoll(), open(), run_wrapper(), scanDevices(), and write().

◆ m_mainloop_signal

QWaitCondition Kwave::PlayBackPulseAudio::m_mainloop_signal
private

wait condition for mainloopWait/mainloopSignal

Definition at line 252 of file PlayBack-PulseAudio.h.

Referenced by close(), connectToServer(), flush(), notifyContext(), notifySinkInfo(), notifyStreamState(), notifySuccess(), notifyWrite(), open(), and scanDevices().

◆ m_mainloop_thread

Kwave::WorkerThread Kwave::PlayBackPulseAudio::m_mainloop_thread
private

worker thread, running the event loop

Definition at line 246 of file PlayBack-PulseAudio.h.

Referenced by connectToServer(), and disconnectFromServer().

◆ m_pa_context

pa_context* Kwave::PlayBackPulseAudio::m_pa_context
private

pulse: context of the connection to the server

Definition at line 285 of file PlayBack-PulseAudio.h.

Referenced by close(), connectToServer(), disconnectFromServer(), flush(), notifyContext(), notifySinkInfo(), open(), scanDevices(), and supportedDevices().

◆ m_pa_mainloop

pa_mainloop* Kwave::PlayBackPulseAudio::m_pa_mainloop
private

pulse: main loop

Definition at line 282 of file PlayBack-PulseAudio.h.

Referenced by close(), connectToServer(), disconnectFromServer(), flush(), run_wrapper(), supportedDevices(), and write().

◆ m_pa_proplist

pa_proplist* Kwave::PlayBackPulseAudio::m_pa_proplist
private

pulse: property list of the context

Definition at line 279 of file PlayBack-PulseAudio.h.

Referenced by connectToServer(), disconnectFromServer(), and open().

◆ m_pa_stream

pa_stream* Kwave::PlayBackPulseAudio::m_pa_stream
private

pulse: playback stream

Definition at line 288 of file PlayBack-PulseAudio.h.

Referenced by close(), flush(), notifyStreamState(), notifySuccess(), notifyWrite(), open(), and write().

◆ m_rate

double Kwave::PlayBackPulseAudio::m_rate
private

sample rate used when opening the device

Definition at line 258 of file PlayBack-PulseAudio.h.

Referenced by close(), flush(), and open().


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