32#include <alsa/asoundlib.h>
38#include <libavcodec/avcodec.h>
39#include <libavfilter/avfilter.h>
40#include <libavfilter/buffersink.h>
41#include <libavfilter/buffersrc.h>
42#include <libavutil/channel_layout.h>
43#include <libavutil/opt.h>
135 for (i = 0; i < size; i += 5) {
146 for (i = 0; i < size; i += 6) {
161 for (i = 0; i < size; i += 8) {
199 for (i = 0; i < n; ++i) {
218 factor = ((INT16_MAX / 8) * 1000U) / (uint32_t) sqrt(avg);
230 LOGDEBUG2(
L_SOUND,
"audio: %s: avg %8d, fac=%6.3f, norm=%6.3f", __FUNCTION__,
249 }
else if (t > INT16_MAX) {
281 factor = (INT16_MAX * 1000) / maxSample;
294 LOGDEBUG2(
L_SOUND,
"audio: %s: max %5d, fac=%6.3f, com=%6.3f", __FUNCTION__, maxSample,
304 }
else if (t > INT16_MAX) {
325 memset(samples, 0, count);
335 }
else if (t > INT16_MAX) {
357 for (i = 0; i < 18; i++) {
426 const AVFilter *abuffer;
427 AVFilterContext *pfilterCtx[3];
429 const AVFilter *aformat;
430 const AVFilter *abuffersink;
431 char channelLayout[64];
432 char optionsStr[1024];
433 int err, i, numFilter = 0;
440 err =
AlsaSetup(audioCtx->ch_layout.nb_channels, audioCtx->sample_rate, 0);
447#if LIBAVFILTER_VERSION_INT < AV_VERSION_INT(7,16,100)
448 avfilter_register_all();
452 LOGERROR(
"audio: %s: Unable to create filter graph.", __FUNCTION__);
457 if (!(abuffer = avfilter_get_by_name(
"abuffer"))) {
458 LOGWARNING(
"audio: %s: Could not find the abuffer filter.", __FUNCTION__);
463 LOGWARNING(
"audio: %s: Could not allocate the m_pBuffersrcCtx instance.", __FUNCTION__);
468 av_channel_layout_describe(&audioCtx->ch_layout, channelLayout,
sizeof(channelLayout));
470 LOGDEBUG2(
L_SOUND,
"audio: %s: IN channelLayout %s sample_fmt %s sample_rate %d channels %d", __FUNCTION__,
471 channelLayout, av_get_sample_fmt_name(audioCtx->sample_fmt), audioCtx->sample_rate, audioCtx->ch_layout.nb_channels);
473 av_opt_set (
m_pBuffersrcCtx,
"channel_layout", channelLayout, AV_OPT_SEARCH_CHILDREN);
474 av_opt_set (
m_pBuffersrcCtx,
"sample_fmt", av_get_sample_fmt_name(audioCtx->sample_fmt), AV_OPT_SEARCH_CHILDREN);
475 av_opt_set_q (
m_pBuffersrcCtx,
"time_base", (AVRational){ 1, audioCtx->sample_rate }, AV_OPT_SEARCH_CHILDREN);
476 av_opt_set_int(
m_pBuffersrcCtx,
"sample_rate", audioCtx->sample_rate, AV_OPT_SEARCH_CHILDREN);
481 LOGWARNING(
"audio: %s: Could not initialize the abuffer filter.", __FUNCTION__);
488 if (!(eq = avfilter_get_by_name(
"superequalizer"))) {
489 LOGWARNING(
"audio: %s: Could not find the superequalizer filter.", __FUNCTION__);
493 if (!(pfilterCtx[numFilter] = avfilter_graph_alloc_filter(
m_pFilterGraph, eq,
"superequalizer"))) {
494 LOGWARNING(
"audio: %s: Could not allocate the superequalizer instance.", __FUNCTION__);
498 snprintf(optionsStr,
sizeof(optionsStr),
"1b=%.2f:2b=%.2f:3b=%.2f:4b=%.2f:5b=%.2f"
499 ":6b=%.2f:7b=%.2f:8b=%.2f:9b=%.2f:10b=%.2f:11b=%.2f:12b=%.2f:13b=%.2f:14b=%.2f:"
505 if (avfilter_init_str(pfilterCtx[numFilter], optionsStr) < 0) {
506 LOGWARNING(
"audio: %s: Could not initialize the superequalizer filter.", __FUNCTION__);
514 AVChannelLayout channel_layout;
516 av_channel_layout_describe(&channel_layout, channelLayout,
sizeof(channelLayout));
517 av_channel_layout_uninit(&channel_layout);
519 LOGDEBUG2(
L_SOUND,
"audio: %s: OUT m_downmix %d m_hwNumChannels %d m_hwSampleRate %d channelLayout %s bytes_per_sample %d",
521 if (!(aformat = avfilter_get_by_name(
"aformat"))) {
522 LOGWARNING(
"audio: %s: Could not find the aformat filter.", __FUNCTION__);
526 if (!(pfilterCtx[numFilter] = avfilter_graph_alloc_filter(
m_pFilterGraph, aformat,
"aformat"))) {
527 LOGWARNING(
"audio: %s: Could not allocate the aformat instance.", __FUNCTION__);
531 snprintf(optionsStr,
sizeof(optionsStr),
532 "sample_fmts=%s:sample_rates=%d:channel_layouts=%s",
533 av_get_sample_fmt_name(AV_SAMPLE_FMT_S16),
m_hwSampleRate, channelLayout);
534 if (avfilter_init_str(pfilterCtx[numFilter], optionsStr) < 0) {
535 LOGWARNING(
"audio: %s: Could not initialize the aformat filter.", __FUNCTION__);
542 if (!(abuffersink = avfilter_get_by_name(
"abuffersink"))) {
543 LOGWARNING(
"audio: %s: Could not find the abuffersink filter.", __FUNCTION__);
547 if (!(pfilterCtx[numFilter] = avfilter_graph_alloc_filter(
m_pFilterGraph, abuffersink,
"sink"))) {
548 LOGWARNING(
"audio: %s: Could not allocate the abuffersink instance.", __FUNCTION__);
552 if (avfilter_init_str(pfilterCtx[numFilter], NULL) < 0) {
553 LOGWARNING(
"audio: %s: Could not initialize the abuffersink instance.", __FUNCTION__);
560 for (i = 0; i < numFilter; i++) {
564 err = avfilter_link(pfilterCtx[i - 1], 0, pfilterCtx[i], 0);
568 LOGWARNING(
"audio: %s: Error connecting audio filters", __FUNCTION__);
575 LOGWARNING(
"audio: %s: Error configuring the audio filter graph", __FUNCTION__);
601 std::lock_guard<std::mutex> lock(
m_mutex);
612 LOGDEBUG2(
L_AV_SYNC,
"audio: %s: dropping %dms audio samples to start in sync with the video (output PTS %s -> %s)",
634 int byteCount = frame->nb_samples * frame->ch_layout.nb_channels *
m_bytesPerSample;
635 buffer = (uint16_t *)frame->data[0];
645 Enqueue((uint16_t *)buffer, byteCount, frame);
647 av_frame_free(&frame);
659 std::lock_guard<std::mutex> lock(
m_mutex);
662 if (n != (
size_t) count)
663 LOGERROR(
"audio: %s: can't place %d samples in ring buffer", __FUNCTION__, count);
689 err =
AlsaSetup(channels, samplerate, passthrough);
691 LOGERROR(
"audio: %s: failed!", __FUNCTION__);
707 AVFrame *outframe =
nullptr;
708 outframe = av_frame_alloc();
710 LOGERROR(
"audio: %s: Error allocating frame", __FUNCTION__);
716 if (err == AVERROR(EAGAIN)) {
718 av_frame_free(&outframe);
719 }
else if (err == AVERROR_EOF) {
720 LOGERROR(
"audio: %s: Error filtering AVERROR_EOF", __FUNCTION__);
721 av_frame_free(&outframe);
722 }
else if (err < 0) {
723 LOGERROR(
"audio: %s: Error filtering the data", __FUNCTION__);
724 av_frame_free(&outframe);
773 AVFrame *outframe = NULL;
780 av_frame_unref(inframe);
788 av_strerror(err, errbuf,
sizeof(errbuf));
789 LOGERROR(
"audio: %s: Error submitting the frame to the filter fmt %s channels %d %s", __FUNCTION__,
790 av_get_sample_fmt_name(ctx->sample_fmt), ctx->ch_layout.nb_channels, errbuf);
791 av_frame_unref(inframe);
817 std::lock_guard<std::mutex> lock(
m_mutex);
837 std::lock_guard<std::mutex> lock(
m_mutex);
865 std::lock_guard<std::mutex> lock(
m_mutex);
886 std::lock_guard<std::mutex> lock(
m_mutex);
891 snd_pcm_sframes_t delayFrames;
895 if (delayFrames < 0) {
929 }
else if (volume > 1000) {
953 snd_pcm_state_t expectedState;
955 expectedState = SND_PCM_STATE_RUNNING;
957 expectedState = SND_PCM_STATE_PAUSED;
960 LOGDEBUG2(
L_SOUND,
"audio: %s: state running, try snd_pcm_pause(1)!", __FUNCTION__);
964 LOGERROR(
"audio: %s: snd_pcm_pause(): %s", __FUNCTION__, snd_strerror(ret));
1062 snd_pcm_state_t state;
1067 LOGERROR(
"audio: %s: Can't recovery from xrun: %s pcm state: %s", __FUNCTION__,
1068 snd_strerror(err), snd_pcm_state_name(state));
1078 snd_pcm_state_t state;
1083 if (state != SND_PCM_STATE_OPEN) {
1085 LOGERROR(
"audio: %s: snd_pcm_drop(): %s", __FUNCTION__, snd_strerror(err));
1088 LOGERROR(
"audio: %s: snd_pcm_prepare(): %s", __FUNCTION__, snd_strerror(err));
1090 LOGDEBUG2(
L_SOUND,
"audio: %s: pcm state %s", __FUNCTION__, snd_pcm_state_name(state));
1130 }
else if (ret == 0) {
1131 LOGERROR(
"audio: %s: snd_pcm_wait() timeout", __FUNCTION__);
1135 std::lock_guard<std::mutex> lock2(
m_mutex);
1139 if (freeAlsaBufferFrameCount < 0) {
1140 if (freeAlsaBufferFrameCount == -EAGAIN)
1144 LOGERROR(
"audio: %s: failed to recover from snd_pcm_avail: %s", __FUNCTION__, snd_strerror(freeAlsaBufferFrameCount));
1146 LOGERROR(
"audio: %s: snd_pcm_avail(): %s", __FUNCTION__, snd_strerror(freeAlsaBufferFrameCount));
1154 if (inputBufferFillLevelBytes == 0)
1157 int bytesToWrite = std::min(snd_pcm_frames_to_bytes(
m_pAlsaPCMHandle, freeAlsaBufferFrameCount), inputBufferFillLevelBytes);
1159 if (bytesToWrite == 0)
1169 int framesToWrite = snd_pcm_bytes_to_frames(
m_pAlsaPCMHandle, bytesToWrite);
1173 framesWritten = snd_pcm_mmap_writei(
m_pAlsaPCMHandle, data, framesToWrite);
1179 if (framesWritten != framesToWrite) {
1180 if (framesWritten < 0) {
1181 if (framesWritten == -EAGAIN)
1184 LOGWARNING(
"audio: %s: writei failed: %s", __FUNCTION__, snd_strerror(framesWritten));
1187 LOGERROR(
"audio: %s: failed to recover from writei: %s", __FUNCTION__, snd_strerror(framesWritten));
1191 LOGWARNING(
"audio: %s: not all frames written", __FUNCTION__);
1215 LOGDEBUG2(
L_SOUND,
"audio: %s: try opening %sdevice '%s'", __FUNCTION__, passthrough ?
"pass-through " :
"", device);
1218 if (!(strchr(device,
':'))) {
1219 sprintf(tmp,
"%s:AES0=%d,AES1=%d,AES2=0,AES3=%d",
1221 IEC958_AES0_NONAUDIO | IEC958_AES0_PRO_EMPHASIS_NONE,
1222 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
1223 IEC958_AES3_CON_FS_48000);
1225 sprintf(tmp,
"%s,AES0=%d,AES1=%d,AES2=0,AES3=%d",
1227 IEC958_AES0_NONAUDIO | IEC958_AES0_PRO_EMPHASIS_NONE,
1228 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
1229 IEC958_AES3_CON_FS_48000);
1231 LOGDEBUG2(
L_SOUND,
"audio: %s: auto append AES: %s -> %s", __FUNCTION__, device, tmp);
1233 sprintf(tmp,
"%s", device);
1238 SND_PCM_NONBLOCK)) < 0) {
1240 LOGWARNING(
"audio: %s: could not open device '%s' error: %s", __FUNCTION__, device, snd_strerror(err));
1244 LOGDEBUG2(
L_SOUND,
"audio: %s: opened %sdevice '%s'", __FUNCTION__, passthrough ?
"pass-through " :
"", device);
1246 return (
char *)device;
1266 err = snd_device_name_hint(-1, devname, (
void ***)&hints);
1268 LOGWARNING(
"audio: %s: Cannot get device names for %s!", __FUNCTION__, hint);
1273 while (*n != NULL) {
1274 name = snd_device_name_get_hint(*n,
"NAME");
1276 if (name && strstr(name, hint)) {
1278 snd_device_name_free_hint((
void **)hints);
1288 snd_device_name_free_hint((
void **)hints);
1297 char *device = NULL;
1298 bool freeDevice =
false;
1319 freeDevice = (device != NULL);
1326 freeDevice = (device != NULL);
1342 LOGFATAL(
"audio: %s: could not open any device, abort!", __FUNCTION__);
1344 if (!strcmp(device,
"null"))
1345 LOGWARNING(
"audio: %s: using %sdevice '%s'", __FUNCTION__,
1348 LOGINFO(
"audio: using %sdevice '%s'",
1356 LOGERROR(
"audio: %s: can't set block mode: %s", __FUNCTION__, snd_strerror(err));
1370 const char *channel;
1371 snd_mixer_t *alsaMixer;
1372 snd_mixer_elem_t *alsaMixerElem;
1373 long alsaMixerElemMin;
1374 long alsaMixerElemMax;
1377 if (!(device = getenv(
"ALSA_MIXER"))) {
1382 if (!(channel = getenv(
"ALSA_MIXER_CHANNEL"))) {
1386 LOGDEBUG2(
L_SOUND,
"audio: %s: mixer %s - %s open", __FUNCTION__, device, channel);
1387 snd_mixer_open(&alsaMixer, 0);
1388 if (alsaMixer && snd_mixer_attach(alsaMixer, device) >= 0
1389 && snd_mixer_selem_register(alsaMixer, NULL, NULL) >= 0
1390 && snd_mixer_load(alsaMixer) >= 0) {
1392 const char *
const alsaMixerElem_name = channel;
1394 alsaMixerElem = snd_mixer_first_elem(alsaMixer);
1395 while (alsaMixerElem) {
1398 name = snd_mixer_selem_get_name(alsaMixerElem);
1399 if (!strcasecmp(name, alsaMixerElem_name)) {
1400 snd_mixer_selem_get_playback_volume_range(alsaMixerElem, &alsaMixerElemMin, &alsaMixerElemMax);
1401 m_alsaRatio = 1000 * (alsaMixerElemMax - alsaMixerElemMin);
1402 LOGDEBUG2(
L_SOUND,
"audio: %s: %s mixer found %ld - %ld ratio %d", __FUNCTION__, channel, alsaMixerElemMin, alsaMixerElemMax,
m_alsaRatio);
1406 alsaMixerElem = snd_mixer_elem_next(alsaMixerElem);
1412 LOGERROR(
"audio: %s: can't open mixer '%s'", __FUNCTION__, device);
1426 snd_mixer_selem_set_playback_volume(
m_pAlsaMixerElem, SND_MIXER_SCHN_FRONT_LEFT, v);
1427 snd_mixer_selem_set_playback_volume(
m_pAlsaMixerElem, SND_MIXER_SCHN_FRONT_RIGHT, v);
1446 snd_pcm_hw_params_t *hwparams;
1447 snd_pcm_state_t state;
1449 unsigned bufferTimeUs = 100'000;
1461 if (state == SND_PCM_STATE_XRUN) {
1462 LOGERROR(
"audio: %s: recover from xrun pcm state: %s", __FUNCTION__, snd_pcm_state_name(state));
1466 snd_pcm_hw_params_alloca(&hwparams);
1468 LOGERROR(
"audio: %s: Read HW config failed! %s", __FUNCTION__, snd_strerror(err));
1472 if (!snd_pcm_hw_params_test_access(
m_pAlsaPCMHandle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) {
1478 LOGERROR(
"audio: %s: SampleRate %d not supported! %s", __FUNCTION__, sample_rate, snd_strerror(err));
1493 if ((err = snd_pcm_hw_params_set_buffer_time_near(
m_pAlsaPCMHandle, hwparams, &bufferTimeUs, NULL)) < 0) {
1494 LOGWARNING(
"audio: %s: bufferTime %d not supported! %s", __FUNCTION__, bufferTimeUs, snd_strerror(err));
1509 LOGERROR(
"audio: %s: set params error: %s\n"
1510 " Channels %d SampleRate %d\n"
1511 " HWChannels %d HWSampleRate %d SampleFormat %s\n"
1512 " Supports pause: %s mmap: %s\n"
1513 " AlsaBufferTime %dms pcm state: %s",
1518 bufferTimeUs / 1000, snd_pcm_state_name(state));
1522 LOGINFO(
"audio: alsa set up:\n"
1523 " Channels %d SampleRate %d%s\n"
1524 " HWChannels %d HWSampleRate %d SampleFormat %s\n"
1525 " Supports pause: %s mmap: %s\n"
1526 " AlsaBufferTime %dms",
1527 channels, sample_rate, passthrough ?
" -> passthrough" :
"",
1529 snd_pcm_format_name(SND_PCM_FORMAT_S16),
1531 bufferTimeUs / 1000);
1542 const char *file, __attribute__ ((unused))
1543 int line, __attribute__ ((unused))
1544 const char *function, __attribute__ ((unused))
1545 int err, __attribute__ ((unused))
1546 const char *fmt, ...)
static void ReorderAudioFrame(uint16_t *buf, int size, int channels)
Reorder audio frame.
static void AlsaNoopCallback(__attribute__((unused)) const char *file, __attribute__((unused)) int line, __attribute__((unused)) const char *function, __attribute__((unused)) int err, __attribute__((unused)) const char *fmt,...)
Empty log callback.
Audio and alsa module header file.
#define NORMALIZE_MAX_INDEX
number of average values
virtual void OnEventReceived(const Event &)=0
void LazyInit(void)
Initialize audio output module.
cSoftHdAudio(cSoftHdDevice *)
cSoftHdAudio constructor
char * OpenAlsaDevice(const char *, int)
Open alsa device.
char * FindAlsaDevice(const char *, const char *, int)
Find alsa device giving some search hints.
bool m_appendAES
flag ato utomatic append AES
void XrunRecovery(void)
xrun recovery
void Filter(AVFrame *, AVCodecContext *)
Send audio frame to filter and enqueue it.
cSoftHdRingbuffer m_pRingbuffer
sample ring buffer
int AlsaSetup(int channels, int sample_rate, int passthrough)
Setup alsa audio for requested format.
int Setup(AVCodecContext *, int, int, int)
Setup alsa.
void Enqueue(uint16_t *, int, AVFrame *)
Send audio data to ringbuffer.
int m_compressionMaxFactor
max. compression factor
cSoftHdDevice * m_pDevice
pointer to device
const char * m_pPCMDevice
PCM device name.
int m_volume
current volume (0 .. 1000)
cAudioThread * m_pAudioThread
pointer to audio thread
virtual ~cSoftHdAudio(void)
cSoftHdAudio denstructor
void SetStereoDescent(int)
Set stereo loudness descent.
int64_t GetHardwareOutputPtsMs(void)
Get the hardware output PTS in milliseconds.
std::mutex m_pauseMutex
mutex for a safe thread pausing
int64_t GetHardwareOutputPtsTimebaseUnits(void)
Get the hardware output PTS in timebase units.
AVFilterContext * m_pBuffersinkCtx
void SetVolume(int)
Set mixer volume (0-1000)
AVFilterContext * m_pBuffersrcCtx
bool m_alsaCanPause
hw supports pause
AVFilterGraph * m_pFilterGraph
int m_passthrough
passthrough mask
const int m_bytesPerSample
number of bytes per sample
const char * m_pMixerChannel
mixer channel name
unsigned int m_hwSampleRate
hardware sample rate in Hz
int64_t PtsToMs(int64_t pts)
IEventReceiver * m_pEventReceiver
pointer to event receiver
void ProcessEvents(void)
Process queued events and forward to event receiver.
int MsToFrames(int milliseconds)
std::vector< Event > m_eventQueue
event queue for incoming events
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
AVRational * m_pTimebase
pointer to AVCodecContext pkts_timebase
bool m_compression
flag to use compress volume
int64_t GetOutputPtsMs(void)
Get the output PTS of the ringbuffer.
bool m_normalize
flag to use volume normalize
AVFrame * FilterGetFrame(void)
Get frame from filter sink.
int m_filterChanged
filter has changed
void AlsaExit(void)
Cleanup alsa audio output module.
void SetCompression(bool, int)
Set volume compression parameters.
snd_mixer_elem_t * m_pAlsaMixerElem
alsa mixer element
void AlsaInit(void)
Initialize alsa audio output module.
void Compress(uint16_t *, int)
Compress audio.
int64_t m_inputPts
pts clock (last pts in ringbuffer)
int m_normalizeFactor
current normalize factor
void AlsaSetVolume(int)
Set alsa mixer volume (0-1000)
int64_t GetOutputPtsMsInternal(void)
cSoftHdConfig * m_pConfig
pointer to config
void Exit(void)
Cleanup audio output module.
int m_amplifier
software volume amplify factor
int GetUsedBytes(void)
Get used bytes in audio ringbuffer.
void SetPaused(bool)
Set audio playback paused state.
void AlsaInitMixer(void)
Initialize alsa mixer.
const char * m_pPassthroughDevice
passthrough device name
void SetPassthrough(int)
Set audio passthrough mask.
int m_normalizeMaxFactor
max. normalize factor
bool m_alsaUseMmap
use mmap
void Normalize(uint16_t *, int)
Normalize audio.
int m_compressionFactor
current compression factor
int64_t MsToPts(int64_t ptsMs)
const int m_normalizeMinFactor
min. normalize factor
const int m_normalizeSamples
number of normalize samples
int m_filterReady
filter is ready
void SetEq(int[18], int)
Set equalizer bands.
int m_normalizeReady
index normalize counter
const char * m_pMixerDevice
mixer device name (not used)
uint32_t m_normalizeAverage[NORMALIZE_MAX_INDEX]
average of n last normalize sample blocks
bool CyclicCall(void)
Cyclic audio playback call.
void AlsaInitPCMDevice(void)
Search for an alsa pcm device and open it.
unsigned int m_hwNumChannels
number of hardware channels
bool m_initialized
class initialized
int FramesToMs(int frames)
int m_stereoDescent
volume descent for stereo
std::mutex m_mutex
mutex for thread safety
int m_alsaRatio
internal -> mixer ratio * 1000
int GetFreeBytes(void)
Get free bytes in audio ringbuffer.
void EnqueueFrame(AVFrame *)
Place samples in audio output queue.
void SoftAmplify(int16_t *, int)
Software amplifier.
void FlushAlsaBuffers(void)
Flush alsa buffers.
void SetNormalize(bool, int)
Set normalize volume parameters.
snd_pcm_t * m_pAlsaPCMHandle
alsa pcm handle
int m_downmix
set stereo downmix
int m_useEqualizer
flag to use equalizer
float m_equalizerBand[18]
equalizer band
snd_mixer_t * m_pAlsaMixer
alsa mixer handle
int m_normalizeIndex
index into normalize average table
int m_normalizeCounter
normalize sample counter
std::atomic< bool > m_paused
audio is paused
int CheckForFilterReady(AVCodecContext *)
Check if the filter has changed and is ready, init the filter if needed.
int InitFilter(AVCodecContext *)
Init filter.
void FlushBuffers(void)
Flush audio buffers.
bool m_softVolume
flag to use soft volume
bool ConfigAudioNormalize
config use normalize volume
int ConfigAudioAutoAES
config automatic AES handling
int ConfigAudioStereoDescent
config reduce stereo loudness
bool ConfigAudioCompression
config use volume compression
bool ConfigAudioPassthroughState
flag audio-passthrough on/off
const char * ConfigAudioPCMDevice
audio PCM device
bool ConfigAudioSoftvol
config use software volume
int ConfigAudioEqBand[18]
config equalizer filter bands
int ConfigAudioMaxCompression
config max volume compression
const char * ConfigAudioMixerChannel
audio mixer channel name
int ConfigAudioEq
config equalizer filter
int ConfigAudioPassthroughMask
config audio pass-through mask
bool ConfigAudioDownmix
config ffmpeg audio downmix
const char * ConfigAudioPassthroughDevice
audio passthrough device
int ConfigAudioMaxNormalize
config max normalize factor
cSoftHdConfig * Config(void)
size_t UsedBytes(void)
Get used bytes in ring buffer.
size_t FreeBytes(void)
Get free bytes in ring buffer.
size_t ReadAdvance(size_t)
Advance read pointer in ring buffer.
size_t GetReadPointer(const void **)
Get read pointer and used bytes at this position of ring buffer.
size_t Write(const void *, size_t)
Write to a ring buffer.
void Reset(void)
Reset ring buffer pointers.
Audio decoder header file.
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, PipEvent > Event
Atomic wrapper macros function header file.
Logger class header file.
#define LOGFATAL
Logger macros.
Misc function header file.
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Workaround for av_err2str() not working with C++.
Ringbuffer class header file.
Thread classes header file.
Rendering class header file.
Videostream class header file.