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 <algorithm>
21 #include <cerrno>
22 #include <cmath>
23 #include <cstdio>
24 #include <cstdlib>
25 #include <cstring>
26 #include <ctime>
27 #include <fcntl.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30 
32 #include "libmythbase/mythdate.h"
33 
34 #include "audiooutputjack.h"
35 
36 #define LOC QString("AOJack: ")
37 
39  AudioOutputBase(settings)
40 {
41  m_ports.fill( nullptr);
42  m_chanVolumes.fill(100);
43 
44  // Set everything up
45  InitSettings(settings);
46  if (settings.m_init)
47  Reconfigure(settings);
48 }
49 
51 {
52  int rate = 0;
53  int i = 0;
54  const char **matching_ports = nullptr;
55  auto *settings = new AudioOutputSettings();
56 
58  if (!m_client)
59  {
60  Error(LOC + tr("Cannot start/connect to jack server "
61  "(to check supported rate/channels)"));
62  delete settings;
63  return nullptr;
64  }
65 
66  if (m_client)
67  rate = jack_get_sample_rate(m_client);
68 
69  if (!rate)
70  {
71  Error(LOC + tr("Unable to retrieve jack server sample rate"));
72  goto err_out;
73  }
74  else
75  {
76  settings->AddSupportedRate(rate);
77  }
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  Error(LOC + 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(reinterpret_cast<void*>(matching_ports));
102  return settings;
103 
104 err_out:
105  // Our abstracted exit point in case of error
106  free(reinterpret_cast<void*>(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  Error(LOC + tr("Requested more channels: (%1), than the maximum: %2")
128  .arg(m_channels).arg(JACK_CHANNELS_MAX));
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  Error(LOC + 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  Error(LOC + 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  Error(LOC + 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  Error(LOC + 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  Error(LOC + tr("Error. Unable to set process callback?!"));
195  if (jack_set_xrun_callback(m_client, JackXRunCallbackHelper, this))
196  Error(LOC + tr("Error. Unable to set xrun callback?!"));
197  if (jack_set_graph_order_callback(m_client, JackGraphOrderCallbackHelper, this))
198  Error(LOC + 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  Error(LOC + 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(reinterpret_cast<void*>(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(reinterpret_cast<void*>(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  {
277  volumes[channel] = 1.0 / 1.0; // ie no effect
278  }
279  }
280 
281  if (m_channels == 2)
282  {
283  for (int frame = 0; frame < nframes; frame++)
284  {
285  bufs[0][frame] = aubuf[sample++] * volumes[0];
286  bufs[1][frame] = aubuf[sample++] * volumes[1];
287  }
288  }
289  else if (m_channels == 6)
290  {
291  for (int frame = 0; frame < nframes; frame++)
292  {
293  // Audio supplied in SMPTE l,r,ce,lfe,lr,rr
294  // We probably want it in ALSA format l,r,lr,rr,ce,lfe
295  bufs[0][frame] = aubuf[sample++] * volumes[0];
296  bufs[1][frame] = aubuf[sample++] * volumes[1];
297  bufs[4][frame] = aubuf[sample++] * volumes[4];
298  bufs[5][frame] = aubuf[sample++] * volumes[5];
299  bufs[2][frame] = aubuf[sample++] * volumes[2];
300  bufs[3][frame] = aubuf[sample++] * volumes[3];
301  }
302  }
303  else if (m_channels == 8)
304  {
305  for (int frame = 0; frame < nframes; frame++)
306  {
307  // Audio supplied in SMPTE l,r,ce,lfe,lr,rr,ml,mr ?
308  // We probably want it in ALSA format l,r,lr,rr,ce,lfe,ml,mr ?
309  // TODO - unknown if this channel ordering is correct?
310  bufs[0][frame] = aubuf[sample++] * volumes[0];
311  bufs[1][frame] = aubuf[sample++] * volumes[1];
312  bufs[4][frame] = aubuf[sample++] * volumes[4];
313  bufs[5][frame] = aubuf[sample++] * volumes[5];
314  bufs[2][frame] = aubuf[sample++] * volumes[2];
315  bufs[3][frame] = aubuf[sample++] * volumes[3];
316  bufs[6][frame] = aubuf[sample++] * volumes[6];
317  bufs[7][frame] = aubuf[sample++] * volumes[7];
318  }
319  }
320  else
321  {
322  for (int frame = 0; frame < nframes; frame++)
323  {
324  // Straightforward de-interleave for all other cases.
325  // Note no channel re-ordering...
326  for (int channel = 0; channel < m_channels; channel++)
327  {
328  bufs[channel][frame] = aubuf[sample++] * volumes[channel];
329  }
330  }
331  }
332 
333 }
334 
335 /* ***************************************************************************
336  Jack Callbacks
337  ****************************************************************************/
338 
339 /* Our Jack callback.
340  Jack will call this from a separate thread whenever it needs "feeding"
341  Simply calls our real code
342 */
343 int AudioOutputJACK::JackCallbackHelper(jack_nframes_t nframes, void *arg)
344 {
345  auto *aoj = static_cast<AudioOutputJACK*>(arg);
346  return aoj->JackCallback(nframes);
347 }
348 
349 /* Useful bit of the callback
350  This callback is called when the sound system requests
351  data. We don't want to block here, because that would
352  just cause dropouts anyway, so we always return whatever
353  data is available. If we haven't received enough, either
354  because we've finished playing or we have a buffer
355  underrun, we play silence to fill the unused space.
356  Return: 0 on success, non zero on error
357 */
358 int AudioOutputJACK::JackCallback(jack_nframes_t nframes)
359 {
360  std::array<float*,JACK_CHANNELS_MAX> bufs {};
361  int bytes_needed = nframes * m_outputBytesPerFrame;
362  int bytes_read = 0;
363 
364  // Check for stale_client set during shutdown callback
366 
367  // Deal with xruns which may have occured
368  // Basically read and discard the data which should have been played
369  int t_jack_xruns = m_jackXruns;
370  for (int i = 0; i < t_jack_xruns; i++)
371  {
372  bytes_read = GetAudioData(m_auBuf, m_fragmentSize, true);
373  VBERROR("Discarded one audio fragment to compensate for xrun");
374  }
375  m_jackXruns -= t_jack_xruns;
376 
377  // Get jack output buffers. Zero out the extra space in the array
378  // to prevent clang-tidy from complaining that DeinterleaveAudio()
379  // can reference a garbage value.
380  int i = 0;
381  for ( ; i < m_channels; i++)
382  bufs[i] = (float*)jack_port_get_buffer(m_ports[i], nframes);
383  for ( ; i < JACK_CHANNELS_MAX; i++)
384  bufs[i] = nullptr;
385 
386  if (m_pauseAudio || m_killAudio)
387  {
388  if (!m_actuallyPaused)
389  {
390  VBAUDIO("JackCallback: audio paused");
392  dispatch(e);
393  m_wasPaused = true;
394  }
395 
396  m_actuallyPaused = true;
397  }
398  else
399  {
400  if (m_wasPaused)
401  {
402  VBAUDIO("JackCallback: Play Event");
404  dispatch(e);
405  m_wasPaused = false;
406  }
407  bytes_read = GetAudioData(m_auBuf, bytes_needed, false);
408  }
409 
410  // Pad with silence
411  if (bytes_needed > bytes_read)
412  {
413  // play silence on buffer underrun
414  memset(m_auBuf + bytes_read, 0, bytes_needed - bytes_read);
415  if (!m_pauseAudio)
416  {
417  VBERROR(QString("Having to insert silence because GetAudioData "
418  "hasn't returned enough data. Wanted: %1 Got: %2")
419  .arg(bytes_needed).arg(bytes_read));
420  }
421  }
422  // Now deinterleave audio (and convert to float)
423  DeinterleaveAudio((float*)m_auBuf, bufs.data(), nframes, m_chanVolumes);
424 
425  if (!m_pauseAudio)
426  {
427  // Output a status event - needed for Music player
428  Status();
429  }
430 
431  return 0;
432 }
433 
434 
435 /* Our Jack XRun callback.
436  Jack will call this from a separate thread whenever an xrun occurs
437  Simply calls our real code
438 */
440 {
441  auto *aoj = static_cast<AudioOutputJACK*>(arg);
442  return aoj->JackXRunCallback();
443 }
444 
445 /* Useful bit of the XRun callback
446  Return: 0 on success, non zero on error
447 */
449 {
450  float delay = jack_get_xrun_delayed_usecs(m_client); // usecs
451  // Increment our counter of "callbacks missed".
452  // All we want to do is chuck away some audio from the ring buffer
453  // to keep our audio output roughly where it should be if we didn't xrun
454  int fragments = (int)ceilf( ((delay / 1000000.0F) * m_sampleRate )
455  / ((float)m_fragmentSize / m_outputBytesPerFrame) );
456  m_jackXruns += fragments; //should be at least 1...
457  VBERROR(QString("Jack XRun Callback: %1 usecs delayed, xruns now %2")
458  .arg(delay).arg(m_jackXruns) );
459 
460  return 0;
461 }
462 
463 /* Our Jack Graph Order Change callback.
464  Jack will call this from a separate thread whenever an xrun occurs
465  Simply calls our real code
466 */
468 {
469  auto *aoj = static_cast<AudioOutputJACK*>(arg);
470  return aoj->JackGraphOrderCallback();
471 }
472 
473 /* Useful bit of the Graph Order Change callback
474  Called when the Jack graph changes. We update our latency info
475  Return: 0 on success, non zero on error
476 */
478 {
479  jack_latency_range_t latency_range;
480  jack_nframes_t max_latency = 0;
481 
482  for (int i = 0; i < m_channels; ++i)
483  {
484  jack_port_get_latency_range( m_ports[i], JackPlaybackLatency, &latency_range );
485  jack_nframes_t port_latency = latency_range.max;
486  max_latency = std::max(port_latency, max_latency);
487  }
488 
489  m_jackLatency = max_latency;
490  VBAUDIO(QString("JACK graph reordered. Maximum latency=%1")
491  .arg(m_jackLatency));
492 
493  return 0;
494 }
495 
496 
497 /* Volume related handling */
499 {
500  int volume = 100;
501  if (m_setInitialVol)
502  {
503  QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
504  controlLabel += "MixerVolume";
505  volume = gCoreContext->GetNumSetting(controlLabel, 80);
506  }
507 
508  m_chanVolumes.fill(volume);
509 }
510 
511 int AudioOutputJACK::GetVolumeChannel(int channel) const
512 {
513  unsigned int vol = 0;
514 
515  if (!m_internalVol)
516  return 100;
517 
518  if (channel < JACK_CHANNELS_MAX)
519  vol = m_chanVolumes[channel];
520 
521  return vol;
522 }
523 
524 void AudioOutputJACK::SetVolumeChannel(int channel, int volume)
525 {
526  if (m_internalVol && (channel < JACK_CHANNELS_MAX))
527  {
528  m_chanVolumes[channel] = volume;
529  if (channel == 0)
530  {
531  // Left
532  m_chanVolumes[2] = volume; // left rear
533  }
534  else if (channel == 1)
535  {
536  // Right
537  m_chanVolumes[3] = volume; // right rear
538  }
539 
540  // LFE and Center
541  m_chanVolumes[4] = m_chanVolumes[5] =
542  (m_chanVolumes[0] + m_chanVolumes[1]) / 2;
543  }
544 }
545 
546 
547 /* We don't need an audio output thread for Jack
548  Everything handled by callbacks here
549  Therefore we can loose all the Start/StopOutputThread, WriteAudio, etc
550 */
552 {
553  return true;
554 }
555 
557 {
558 }
559 
560 // Don't need WriteAudio - this is only for the base class audio loop
561 void AudioOutputJACK::WriteAudio([[maybe_unused]] unsigned char *aubuf,
562  [[maybe_unused]] int size)
563 {
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  Error(LOC + 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  Error(LOC + 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: */
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:20
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:31
AudioOutput::Error
void Error(const QString &msg)
Definition: audiooutput.cpp:276
LOC
#define LOC
Definition: audiooutputjack.cpp:36
AudioOutputJACK::OpenDevice
bool OpenDevice(void) override
Definition: audiooutputjack.cpp:119
VolumeBase::m_internalVol
bool m_internalVol
Definition: volumebase.h:43
AudioOutputJACK::m_jackLatency
int m_jackLatency
Definition: audiooutputjack.h:68
AudioOutputBase::KillAudio
void KillAudio(void)
Kill the output thread and cleanup.
Definition: audiooutputbase.cpp:870
AudioOutputJACK::JackGraphOrderCallback
int JackGraphOrderCallback()
Definition: audiooutputjack.cpp:477
AudioOutputJACK
Definition: audiooutputjack.h:19
VBERROR
#define VBERROR(str)
Definition: audiooutputbase.h:23
AudioOutputJACK::StartOutputThread
bool StartOutputThread(void) override
Definition: audiooutputjack.cpp:551
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
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:180
AudioOutputJACK::StopOutputThread
void StopOutputThread(void) override
Definition: audiooutputjack.cpp:556
AudioOutputBase::m_killAudio
bool m_killAudio
Definition: audiooutputbase.h:197
audiooutputjack.h
AudioSettings
Definition: audiosettings.h:28
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:185
AudioOutputJACK::JackCallback
int JackCallback(jack_nframes_t nframes)
Definition: audiooutputjack.cpp:358
AudioOutputJACK::GetOutputSettings
AudioOutputSettings * GetOutputSettings(bool digital) override
Definition: audiooutputjack.cpp:50
mythdate.h
OutputEvent::kStopped
static const Type kStopped
Definition: output.h:67
AudioOutputBase
Definition: audiooutputbase.h:51
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:343
AudioOutputJACK::m_auBuf
unsigned char * m_auBuf
Definition: audiooutputjack.h:70
AudioOutputBase::Reconfigure
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
Definition: audiooutputbase.cpp:472
AudioOutputJACK::WriteAudio
void WriteAudio(unsigned char *aubuf, int size) override
Definition: audiooutputjack.cpp:561
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:1752
AudioOutputJACK::m_jackXruns
int m_jackXruns
Definition: audiooutputjack.h:69
AudioOutputJACK::VolumeInit
void VolumeInit(void)
Definition: audiooutputjack.cpp:498
AudioOutputBase::m_pauseAudio
bool m_pauseAudio
Definition: audiooutputbase.h:199
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
OutputEvent::kPlaying
static const Type kPlaying
Definition: output.h:63
JACK_CHANNELS_MAX
static constexpr int8_t JACK_CHANNELS_MAX
Definition: audiooutputjack.h:14
AudioOutputBase::m_channels
int m_channels
Definition: audiooutputbase.h:174
AudioOutputBase::m_setInitialVol
bool m_setInitialVol
Definition: audiooutputbase.h:203
AudioOutputJACK::JackXRunCallbackHelper
static int JackXRunCallbackHelper(void *arg)
Definition: audiooutputjack.cpp:439
AudioOutputBase::Status
virtual void Status(void)
Report status via an OutputEvent.
Definition: audiooutputbase.cpp:1624
AudioOutputBase::m_outputBytesPerFrame
int m_outputBytesPerFrame
Definition: audiooutputbase.h:177
mythcorecontext.h
AudioOutputBase::m_actuallyPaused
bool m_actuallyPaused
Definition: audiooutputbase.h:200
AudioOutputBase::m_wasPaused
bool m_wasPaused
Definition: audiooutputbase.h:201
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:48
AudioOutputJACK::m_chanVolumes
jack_vol_array m_chanVolumes
Definition: audiooutputjack.h:65
AudioOutputBase::InitSettings
void InitSettings(const AudioSettings &settings)
Definition: audiooutputbase.cpp:119
AudioOutputJACK::JackGraphOrderCallbackHelper
static int JackGraphOrderCallbackHelper(void *arg)
Definition: audiooutputjack.cpp:467
AudioOutputJACK::CloseDevice
void CloseDevice(void) override
Definition: audiooutputjack.cpp:224
AudioOutputJACK::AudioOutputJACK
AudioOutputJACK(const AudioSettings &settings)
Definition: audiooutputjack.cpp:38
AudioOutputBase::m_fragmentSize
int m_fragmentSize
Definition: audiooutputbase.h:182
AudioOutputJACK::JackXRunCallback
int JackXRunCallback()
Definition: audiooutputjack.cpp:448
FORMAT_FLT
@ FORMAT_FLT
Definition: audiooutputsettings.h:31
AudioOutputJACK::SetVolumeChannel
void SetVolumeChannel(int channel, int volume) override
Definition: audiooutputjack.cpp:524
AudioOutputJACK::~AudioOutputJACK
~AudioOutputJACK() override
Definition: audiooutputjack.cpp:113
AudioOutputJACK::m_client
jack_client_t * m_client
Definition: audiooutputjack.h:66
OutputEvent::kPaused
static const Type kPaused
Definition: output.h:66
AudioOutputJACK::GetVolumeChannel
int GetVolumeChannel(int channel) const override
Definition: audiooutputjack.cpp:511
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902