MythTV  master
audiooutputjack.cpp
Go to the documentation of this file.
1 /*
2  * JACK AudioOutput module
3  * Written by Ed Wildgoose in 2010 with improvements from various authors
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 #include <cerrno>
21 #include <cmath>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 #include <ctime>
26 #include <fcntl.h>
27 #include <sys/time.h>
28 #include <unistd.h>
29 
30 #include <iostream>
31 
32 #include "mythcorecontext.h"
33 #include "audiooutputjack.h"
34 #include "mythdate.h"
35 
36 #define LOC QString("AOJack: ")
37 
38 #define JERROR(str) Error(LOC + (str))
39 
41  AudioOutputBase(settings)
42 {
43  m_ports.fill( nullptr);
44  m_chanVolumes.fill(100);
45 
46  // Set everything up
47  InitSettings(settings);
48  if (settings.m_init)
49  Reconfigure(settings);
50 }
51 
53 {
54  int rate = 0;
55  int i = 0;
56  const char **matching_ports = nullptr;
57  auto *settings = new AudioOutputSettings();
58 
60  if (!m_client)
61  {
62  JERROR(tr("Cannot start/connect to jack server "
63  "(to check supported rate/channels)"));
64  delete settings;
65  return nullptr;
66  }
67 
68  if (m_client)
69  rate = jack_get_sample_rate(m_client);
70 
71  if (!rate)
72  {
73  JERROR(tr("Unable to retrieve jack server sample rate"));
74  goto err_out;
75  }
76  else
77  settings->AddSupportedRate(rate);
78 
79  // Jack only wants float format samples (de-interleaved for preference)
80  settings->AddSupportedFormat(FORMAT_FLT);
81 
82  // Find some Jack ports to connect to
83  matching_ports = JackGetPorts();
84 
85  if (!matching_ports || !matching_ports[0])
86  {
87  JERROR(tr("No ports available to connect to"));
88  goto err_out;
89  }
90  // Count matching ports from 2nd port upwards
91  i = 1;
92  while ((i < JACK_CHANNELS_MAX) && matching_ports[i])
93  {
94  settings->AddSupportedChannels(i+1);
95  VBAUDIO(QString("Adding channels: %1").arg(i+1));
96  i++;
97  }
98 
99  // Currently this looks very similar to error code - duplicated for safety
100  free(matching_ports);
102  return settings;
103 
104 err_out:
105  // Our abstracted exit point in case of error
106  free(matching_ports);
108  delete settings;
109  return nullptr;
110 }
111 
112 
114 {
115  // Close down all audio stuff
116  KillAudio();
117 }
118 
120 {
121  const char **matching_ports = nullptr;
122  int i = 0;
123 
124  // We have a hard coded channel limit - check we haven't exceeded it
126  {
127  JERROR(tr("Requested more channels: (%1), than the maximum: %2")
129  return false;
130  }
131 
132  VBAUDIO( QString("Opening JACK audio device: '%1'.")
133  .arg(m_mainDevice));
134 
135  // Setup volume control
136  if (m_internalVol)
137  VolumeInit();
138 
139  // Connect to the Jack audio server
141  if (!m_client)
142  {
143  JERROR(tr("Cannot start/connect to jack server"));
144  goto err_out;
145  }
146 
147  // Find some Jack ports to connect to
148  matching_ports = JackGetPorts();
149  if (!matching_ports || !matching_ports[0])
150  {
151  JERROR(tr("No ports available to connect to"));
152  goto err_out;
153  }
154 
155  // Count matching ports
156  i = 1;
157  while (matching_ports[i])
158  i++;
159  // ensure enough ports to satisfy request
160  if (m_channels > i)
161  {
162  JERROR(tr("Not enough ports available to connect to"));
163  goto err_out;
164  }
165 
166  // Create our output ports
167  for (i = 0; i < m_channels; i++)
168  {
169  QString port_name = QString("out_%1").arg(i);
170  m_ports[i] = jack_port_register(m_client, port_name.toLatin1().constData(),
171  JACK_DEFAULT_AUDIO_TYPE,
172  JackPortIsOutput, 0);
173  if (!m_ports[i])
174  {
175  JERROR(tr("Error while registering new jack port: %1").arg(i));
176  goto err_out;
177  }
178  }
179 
180  // Note some basic soundserver parameters
181  m_sampleRate = jack_get_sample_rate(m_client);
182 
183  // Get the size of our callback buffer in bytes
184  m_fragmentSize = jack_get_buffer_size(m_client) * m_outputBytesPerFrame;
185 
186  // Allocate a new temp buffer to de-interleave our audio data
187  delete[] m_auBuf;
188  m_auBuf = new unsigned char[m_fragmentSize];
189 
190  // Set our callbacks
191  // These will actually get called after jack_activate()!
192  // ...Possibly even before this OpenDevice sub returns...
193  if (jack_set_process_callback(m_client, JackCallbackHelper, this))
194  JERROR(tr("Error. Unable to set process callback?!"));
195  if (jack_set_xrun_callback(m_client, JackXRunCallbackHelper, this))
196  JERROR(tr("Error. Unable to set xrun callback?!"));
197  if (jack_set_graph_order_callback(m_client, JackGraphOrderCallbackHelper, this))
198  JERROR(tr("Error. Unable to set graph order change callback?!"));
199 
200  // Activate! Everything comes into life after here. Beware races
201  if (jack_activate(m_client))
202  {
203  JERROR(tr("Calling jack_activate failed"));
204  goto err_out;
205  }
206 
207  // Connect our output ports
208  if (! JackConnectPorts(matching_ports))
209  goto err_out;
210 
211  // Free up some stuff
212  free(matching_ports);
213 
214  // Device opened successfully
215  return true;
216 
217 err_out:
218  // Our abstracted exit point in case of error
219  free(matching_ports);
221  return false;
222 }
223 
225 {
228  if (m_auBuf)
229  {
230  delete[] m_auBuf;
231  m_auBuf = nullptr;
232  }
233 
234  VBAUDIO("Jack: Stop Event");
236  dispatch(e);
237 }
238 
239 
241 {
242  int frames_played = jack_frames_since_cycle_start (this->m_client);
243  LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO,
244  QString("Stats: frames_since_cycle_start:%1 fragment_size:%2")
245  .arg(frames_played).arg(m_fragmentSize));
246  return (m_fragmentSize * 2) - (frames_played * m_outputBytesPerFrame);
247 }
248 
249 /* Converts buffer to jack buffers
250  Input: aubuf: interleaved buffer of currently assumed to be 32bit floats
251  nframes: number of frames of output required
252  Output: bufs: non interleaved float values.
253 */
254 void AudioOutputJACK::DeinterleaveAudio(const float *aubuf, float **bufs, int nframes,
255  const jack_vol_array& channel_volumes)
256 {
257  // Convert to floats and de-interleave
258  // TODO: Implicit assumption dealing with float input only.
259  short sample = 0;
260 
261  // Create a local float version of the channel_volumes array
262  // TODO: This can probably be removed
263  // if we have float software volume control in AOB?
264  std::array<float,JACK_CHANNELS_MAX> volumes {};
265  for (int channel = 0; channel < m_channels; channel++)
266  {
267  if (m_internalVol)
268  {
269  // Software volume control - we use an exponential adjustment
270  // (perhaps should be log?)
271  volumes[channel] = (float) (( channel_volumes[channel] *
272  channel_volumes[channel] ) /
273  10000.0);
274  }
275  else
276  volumes[channel] = 1.0 / 1.0; // ie no effect
277  }
278 
279  if (m_channels == 2)
280  {
281  for (int frame = 0; frame < nframes; frame++)
282  {
283  bufs[0][frame] = aubuf[sample++] * volumes[0];
284  bufs[1][frame] = aubuf[sample++] * volumes[1];
285  }
286  }
287  else if (m_channels == 6)
288  {
289  for (int frame = 0; frame < nframes; frame++)
290  {
291  // Audio supplied in SMPTE l,r,ce,lfe,lr,rr
292  // We probably want it in ALSA format l,r,lr,rr,ce,lfe
293  bufs[0][frame] = aubuf[sample++] * volumes[0];
294  bufs[1][frame] = aubuf[sample++] * volumes[1];
295  bufs[4][frame] = aubuf[sample++] * volumes[4];
296  bufs[5][frame] = aubuf[sample++] * volumes[5];
297  bufs[2][frame] = aubuf[sample++] * volumes[2];
298  bufs[3][frame] = aubuf[sample++] * volumes[3];
299  }
300  }
301  else if (m_channels == 8)
302  {
303  for (int frame = 0; frame < nframes; frame++)
304  {
305  // Audio supplied in SMPTE l,r,ce,lfe,lr,rr,ml,mr ?
306  // We probably want it in ALSA format l,r,lr,rr,ce,lfe,ml,mr ?
307  // TODO - unknown if this channel ordering is correct?
308  bufs[0][frame] = aubuf[sample++] * volumes[0];
309  bufs[1][frame] = aubuf[sample++] * volumes[1];
310  bufs[4][frame] = aubuf[sample++] * volumes[4];
311  bufs[5][frame] = aubuf[sample++] * volumes[5];
312  bufs[2][frame] = aubuf[sample++] * volumes[2];
313  bufs[3][frame] = aubuf[sample++] * volumes[3];
314  bufs[6][frame] = aubuf[sample++] * volumes[6];
315  bufs[7][frame] = aubuf[sample++] * volumes[7];
316  }
317  }
318  else
319  {
320  for (int frame = 0; frame < nframes; frame++)
321  {
322  // Straightforward de-interleave for all other cases.
323  // Note no channel re-ordering...
324  for (int channel = 0; channel < m_channels; channel++)
325  {
326  bufs[channel][frame] = aubuf[sample++] * volumes[channel];
327  }
328  }
329  }
330 
331 }
332 
333 /* ***************************************************************************
334  Jack Callbacks
335  ****************************************************************************/
336 
337 /* Our Jack callback.
338  Jack will call this from a separate thread whenever it needs "feeding"
339  Simply calls our real code
340 */
341 int AudioOutputJACK::JackCallbackHelper(jack_nframes_t nframes, void *arg)
342 {
343  auto *aoj = static_cast<AudioOutputJACK*>(arg);
344  return aoj->JackCallback(nframes);
345 }
346 
347 /* Useful bit of the callback
348  This callback is called when the sound system requests
349  data. We don't want to block here, because that would
350  just cause dropouts anyway, so we always return whatever
351  data is available. If we haven't received enough, either
352  because we've finished playing or we have a buffer
353  underrun, we play silence to fill the unused space.
354  Return: 0 on success, non zero on error
355 */
356 int AudioOutputJACK::JackCallback(jack_nframes_t nframes)
357 {
358  std::array<float*,JACK_CHANNELS_MAX> bufs {};
359  int bytes_needed = nframes * m_outputBytesPerFrame;
360  int bytes_read = 0;
361 
362  // Check for stale_client set during shutdown callback
364 
365  // Deal with xruns which may have occured
366  // Basically read and discard the data which should have been played
367  int t_jack_xruns = m_jackXruns;
368  for (int i = 0; i < t_jack_xruns; i++)
369  {
370  bytes_read = GetAudioData(m_auBuf, m_fragmentSize, true);
371  VBERROR("Discarded one audio fragment to compensate for xrun");
372  }
373  m_jackXruns -= t_jack_xruns;
374 
375  // Get jack output buffers. Zero out the extra space in the array
376  // to prevent clang-tidy from complaining that DeinterleaveAudio()
377  // can reference a garbage value.
378  int i = 0;
379  for ( ; i < m_channels; i++)
380  bufs[i] = (float*)jack_port_get_buffer(m_ports[i], nframes);
381  for ( ; i < JACK_CHANNELS_MAX; i++)
382  bufs[i] = nullptr;
383 
384  if (m_pauseAudio || m_killAudio)
385  {
386  if (!m_actuallyPaused)
387  {
388  VBAUDIO("JackCallback: audio paused");
390  dispatch(e);
391  m_wasPaused = true;
392  }
393 
394  m_actuallyPaused = true;
395  }
396  else
397  {
398  if (m_wasPaused)
399  {
400  VBAUDIO("JackCallback: Play Event");
402  dispatch(e);
403  m_wasPaused = false;
404  }
405  bytes_read = GetAudioData(m_auBuf, bytes_needed, false);
406  }
407 
408  // Pad with silence
409  if (bytes_needed > bytes_read)
410  {
411  // play silence on buffer underrun
412  memset(m_auBuf + bytes_read, 0, bytes_needed - bytes_read);
413  if (!m_pauseAudio)
414  {
415  VBERROR(QString("Having to insert silence because GetAudioData "
416  "hasn't returned enough data. Wanted: %1 Got: %2")
417  .arg(bytes_needed).arg(bytes_read));
418  }
419  }
420  // Now deinterleave audio (and convert to float)
421  DeinterleaveAudio((float*)m_auBuf, bufs.data(), nframes, m_chanVolumes);
422 
423  if (!m_pauseAudio)
424  {
425  // Output a status event - needed for Music player
426  Status();
427  }
428 
429  return 0;
430 }
431 
432 
433 /* Our Jack XRun callback.
434  Jack will call this from a separate thread whenever an xrun occurs
435  Simply calls our real code
436 */
438 {
439  auto *aoj = static_cast<AudioOutputJACK*>(arg);
440  return aoj->JackXRunCallback();
441 }
442 
443 /* Useful bit of the XRun callback
444  Return: 0 on success, non zero on error
445 */
447 {
448  float delay = jack_get_xrun_delayed_usecs(m_client); // usecs
449  // Increment our counter of "callbacks missed".
450  // All we want to do is chuck away some audio from the ring buffer
451  // to keep our audio output roughly where it should be if we didn't xrun
452  int fragments = (int)ceilf( ((delay / 1000000.0F) * m_sampleRate )
453  / ((float)m_fragmentSize / m_outputBytesPerFrame) );
454  m_jackXruns += fragments; //should be at least 1...
455  VBERROR(QString("Jack XRun Callback: %1 usecs delayed, xruns now %2")
456  .arg(delay).arg(m_jackXruns) );
457 
458  return 0;
459 }
460 
461 /* Our Jack Graph Order Change callback.
462  Jack will call this from a separate thread whenever an xrun occurs
463  Simply calls our real code
464 */
466 {
467  auto *aoj = static_cast<AudioOutputJACK*>(arg);
468  return aoj->JackGraphOrderCallback();
469 }
470 
471 /* Useful bit of the Graph Order Change callback
472  Called when the Jack graph changes. We update our latency info
473  Return: 0 on success, non zero on error
474 */
476 {
477  jack_latency_range_t latency_range;
478  jack_nframes_t max_latency = 0;
479 
480  for (int i = 0; i < m_channels; ++i)
481  {
482  jack_port_get_latency_range( m_ports[i], JackPlaybackLatency, &latency_range );
483  jack_nframes_t port_latency = latency_range.max;
484  if (port_latency > max_latency)
485  max_latency = port_latency;
486  }
487 
488  m_jackLatency = max_latency;
489  VBAUDIO(QString("JACK graph reordered. Maximum latency=%1")
490  .arg(m_jackLatency));
491 
492  return 0;
493 }
494 
495 
496 /* Volume related handling */
498 {
499  int volume = 100;
500  if (m_setInitialVol)
501  {
502  QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
503  controlLabel += "MixerVolume";
504  volume = gCoreContext->GetNumSetting(controlLabel, 80);
505  }
506 
507  m_chanVolumes.fill(volume);
508 }
509 
511 {
512  unsigned int vol = 0;
513 
514  if (!m_internalVol)
515  return 100;
516 
518  vol = m_chanVolumes[channel];
519 
520  return vol;
521 }
522 
524 {
526  {
527  m_chanVolumes[channel] = volume;
528  if (channel == 0)
529  {
530  // Left
531  m_chanVolumes[2] = volume; // left rear
532  }
533  else if (channel == 1)
534  {
535  // Right
536  m_chanVolumes[3] = volume; // right rear
537  }
538 
539  // LFE and Center
540  m_chanVolumes[4] = m_chanVolumes[5] =
541  (m_chanVolumes[0] + m_chanVolumes[1]) / 2;
542  }
543 }
544 
545 
546 /* We don't need an audio output thread for Jack
547  Everything handled by callbacks here
548  Therefore we can loose all the Start/StopOutputThread, WriteAudio, etc
549 */
551 {
552  return true;
553 }
554 
556 {
557 }
558 
559 // Don't need WriteAudio - this is only for the base class audio loop
560 void AudioOutputJACK::WriteAudio(unsigned char *aubuf, int size)
561 {
562  (void)aubuf;
563  (void)size;
564  // unneeded and unused in JACK
565 }
566 
567 /* **********************************************
568  Jack wrapper and convenience functions
569  ***********************************************/
570 
572 {
573  QString client_name = QString("mythtv_%1").arg(getpid());
574  auto open_options = (jack_options_t)(JackUseExactName | JackNoStartServer);
575  jack_status_t open_status = JackFailure;
576 
577  jack_client_t *client = jack_client_open(client_name.toLatin1().constData(),
578  open_options, &open_status);
579 
580  return client;
581 }
582 
584 {
585  const char **matching_ports = nullptr;
586  unsigned long port_flags=JackPortIsInput;
587  const char *port_name = nullptr;
588 
589  // Have we been given a target port to connect to
590  if (!m_mainDevice.isEmpty())
591  {
592  port_name = m_mainDevice.toLatin1().constData();
593  }
594  else
595  {
596  port_flags |= JackPortIsPhysical;
597  }
598 
599  // list matching ports
600  matching_ports = jack_get_ports(m_client, port_name, nullptr, port_flags);
601  return matching_ports;
602 }
603 
604 
605 bool AudioOutputJACK::JackConnectPorts(const char** matching_ports)
606 {
607  int i=0;
608 
609  // Connect our output ports
610  for (i = 0; i < m_channels; i++)
611  {
612  if (jack_connect(m_client, jack_port_name(m_ports[i]), matching_ports[i]))
613  {
614  JERROR(tr("Calling jack_connect failed on port: %1\n").arg(i));
615  return false;
616  }
617  }
618 
619  return true;
620 }
621 
622 void AudioOutputJACK::JackClientClose(jack_client_t **client)
623 {
624  if (*client)
625  {
626  int err = jack_client_close(*client);
627  if (err != 0)
628  JERROR(tr("Error closing Jack output device. Error: %1")
629  .arg(err));
630  *client = nullptr;
631  }
632 }
633 
634 /* vim: set expandtab tabstop=4 shiftwidth=4: */
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1420
channel
QDomElement channel
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:501
AudioOutputJACK::m_staleClient
jack_client_t * m_staleClient
Definition: audiooutputjack.h:67
AudioOutputJACK::JackClientOpen
static jack_client_t * JackClientOpen(void)
Definition: audiooutputjack.cpp:571
AudioOutputJACK::JackGetPorts
const char ** JackGetPorts(void)
Definition: audiooutputjack.cpp:583
VBAUDIO
#define VBAUDIO(str)
Definition: audiooutputbase.h:19
AudioOutputJACK::JackClientClose
void JackClientClose(jack_client_t **client)
Definition: audiooutputjack.cpp:622
AudioOutputJACK::JackConnectPorts
bool JackConnectPorts(const char **)
Definition: audiooutputjack.cpp:605
OutputEvent
Definition: output.h:30
OutputEvent::Stopped
static Type Stopped
Definition: output.h:67
AudioOutputJACK::OpenDevice
bool OpenDevice(void) override
Definition: audiooutputjack.cpp:119
VolumeBase::m_internalVol
bool m_internalVol
Definition: volumebase.h:41
AudioOutputJACK::m_jackLatency
int m_jackLatency
Definition: audiooutputjack.h:68
AudioOutputBase::KillAudio
void KillAudio(void)
Kill the output thread and cleanup.
Definition: audiooutputbase.cpp:857
AudioOutputJACK::JackGraphOrderCallback
int JackGraphOrderCallback()
Definition: audiooutputjack.cpp:475
AudioOutputJACK
Definition: audiooutputjack.h:20
arg
arg(title).arg(filename).arg(doDelete))
VBERROR
#define VBERROR(str)
Definition: audiooutputbase.h:22
AudioOutputJACK::StartOutputThread
bool StartOutputThread(void) override
Definition: audiooutputjack.cpp:550
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
AudioOutputJACK::m_ports
jack_port_array m_ports
Definition: audiooutputjack.h:64
MythObservable::dispatch
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
Definition: mythobservable.cpp:73
AudioOutputBase::m_sampleRate
int m_sampleRate
Definition: audiooutputbase.h:177
AudioOutputJACK::StopOutputThread
void StopOutputThread(void) override
Definition: audiooutputjack.cpp:555
AudioOutputBase::m_killAudio
bool m_killAudio
Definition: audiooutputbase.h:194
audiooutputjack.h
AudioSettings
Definition: audiosettings.h:29
jack_vol_array
std::array< int, JACK_CHANNELS_MAX > jack_vol_array
Definition: audiooutputjack.h:17
AudioOutputBase::m_mainDevice
QString m_mainDevice
Definition: audiooutputbase.h:182
AudioOutputJACK::JackCallback
int JackCallback(jack_nframes_t nframes)
Definition: audiooutputjack.cpp:356
AudioOutputJACK::GetOutputSettings
AudioOutputSettings * GetOutputSettings(bool digital) override
Definition: audiooutputjack.cpp:52
mythdate.h
AudioOutputBase
Definition: audiooutputbase.h:50
OutputEvent::Playing
static Type Playing
Definition: output.h:63
AudioSettings::m_init
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
Definition: audiosettings.h:85
AudioOutputJACK::GetBufferedOnSoundcard
int GetBufferedOnSoundcard(void) const override
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
Definition: audiooutputjack.cpp:240
AudioOutputJACK::JackCallbackHelper
static int JackCallbackHelper(jack_nframes_t nframes, void *arg)
Definition: audiooutputjack.cpp:341
AudioOutputJACK::m_auBuf
unsigned char * m_auBuf
Definition: audiooutputjack.h:70
FORMAT_FLT
@ FORMAT_FLT
Definition: audiooutputsettings.h:32
AudioOutputBase::Reconfigure
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
Definition: audiooutputbase.cpp:465
AudioOutputJACK::WriteAudio
void WriteAudio(unsigned char *aubuf, int size) override
Definition: audiooutputjack.cpp:560
AudioOutputBase::GetAudioData
int GetAudioData(uchar *buffer, int buf_size, bool full_buffer, volatile uint *local_raud=nullptr)
Copy frames from the audiobuffer into the buffer provided.
Definition: audiooutputbase.cpp:1729
AudioOutputJACK::m_jackXruns
int m_jackXruns
Definition: audiooutputjack.h:69
AudioOutputJACK::VolumeInit
void VolumeInit(void)
Definition: audiooutputjack.cpp:497
AudioOutputBase::m_pauseAudio
bool m_pauseAudio
Definition: audiooutputbase.h:196
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
JACK_CHANNELS_MAX
#define JACK_CHANNELS_MAX
Definition: audiooutputjack.h:14
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:933
JERROR
#define JERROR(str)
Definition: audiooutputjack.cpp:38
AudioOutputBase::m_channels
int m_channels
Definition: audiooutputbase.h:171
AudioOutputBase::m_setInitialVol
bool m_setInitialVol
Definition: audiooutputbase.h:200
OutputEvent::Paused
static Type Paused
Definition: output.h:66
AudioOutputJACK::JackXRunCallbackHelper
static int JackXRunCallbackHelper(void *arg)
Definition: audiooutputjack.cpp:437
AudioOutputBase::Status
virtual void Status(void)
Report status via an OutputEvent.
Definition: audiooutputbase.cpp:1599
AudioOutputBase::m_outputBytesPerFrame
int m_outputBytesPerFrame
Definition: audiooutputbase.h:174
mythcorecontext.h
AudioOutputBase::m_actuallyPaused
bool m_actuallyPaused
Definition: audiooutputbase.h:197
AudioOutputBase::m_wasPaused
bool m_wasPaused
Definition: audiooutputbase.h:198
AudioOutputJACK::DeinterleaveAudio
void DeinterleaveAudio(const float *aubuf, float **bufs, int nframes, const jack_vol_array &channel_volumes)
Definition: audiooutputjack.cpp:254
AudioOutputSettings
Definition: audiooutputsettings.h:50
AudioOutputJACK::m_chanVolumes
jack_vol_array m_chanVolumes
Definition: audiooutputjack.h:65
AudioOutputBase::InitSettings
void InitSettings(const AudioSettings &settings)
Definition: audiooutputbase.cpp:117
AudioOutputJACK::JackGraphOrderCallbackHelper
static int JackGraphOrderCallbackHelper(void *arg)
Definition: audiooutputjack.cpp:465
AudioOutputJACK::CloseDevice
void CloseDevice(void) override
Definition: audiooutputjack.cpp:224
AudioOutputJACK::AudioOutputJACK
AudioOutputJACK(const AudioSettings &settings)
Definition: audiooutputjack.cpp:40
AudioOutputBase::m_fragmentSize
int m_fragmentSize
Definition: audiooutputbase.h:179
AudioOutputJACK::JackXRunCallback
int JackXRunCallback()
Definition: audiooutputjack.cpp:446
AudioOutputJACK::SetVolumeChannel
void SetVolumeChannel(int channel, int volume) override
Definition: audiooutputjack.cpp:523
AudioOutputJACK::~AudioOutputJACK
~AudioOutputJACK() override
Definition: audiooutputjack.cpp:113
AudioOutputJACK::m_client
jack_client_t * m_client
Definition: audiooutputjack.h:66
AudioOutputJACK::GetVolumeChannel
int GetVolumeChannel(int channel) const override
Definition: audiooutputjack.cpp:510
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:919