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