40 : m_pPCMDevice(m_pConfig->ConfigAudioPCMDevice),
41 m_pMixerChannel(m_pConfig->ConfigAudioMixerChannel),
42 m_appendAES(m_pConfig->ConfigAudioAutoAES),
43 m_passthroughMask(m_pConfig->ConfigAudioPassthroughState ? m_pConfig->ConfigAudioPassthroughMask : 0),
44 m_downmix(m_pConfig->ConfigAudioDownmix)
102 LOGDEBUG2(
L_SOUND,
"audio: %s: try opening device '%s'", __FUNCTION__, device);
105 if (!(strchr(device,
':')))
106 snprintf(prefix,
sizeof(prefix),
"%s:", device);
108 snprintf(prefix,
sizeof(prefix),
"%s,", device);
110 snprintf(tmp,
sizeof(tmp),
"%sAES0=%d,AES1=%d,AES2=0,AES3=%d",
112 IEC958_AES0_NONAUDIO | IEC958_AES0_PRO_EMPHASIS_NONE,
113 IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
114 IEC958_AES3_CON_FS_48000);
116 LOGDEBUG2(
L_SOUND,
"audio: %s: auto append AES: %s -> %s", __FUNCTION__, device, tmp);
118 snprintf(tmp,
sizeof(tmp),
"%s", device);
122 if ((err = snd_pcm_open(&
m_pPCMHandle, tmp, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
123 LOGWARNING(
"audio: %s: could not open device '%s' error: %s", __FUNCTION__, device, snd_strerror(err));
129 return (
char *)device;
148 err = snd_device_name_hint(-1, devname, (
void ***)&hints);
150 LOGWARNING(
"audio: %s: Cannot get device names for %s!", __FUNCTION__, hint);
156 name = snd_device_name_get_hint(*n,
"NAME");
158 if (name && strstr(name, hint)) {
160 snd_device_name_free_hint((
void **)hints);
170 snd_device_name_free_hint((
void **)hints);
252 snd_mixer_t *alsaMixer;
253 snd_mixer_elem_t *alsaMixerElem;
254 long alsaMixerElemMin;
255 long alsaMixerElemMax;
257 if (!(device = getenv(
"ALSA_MIXER"))) {
262 if (!(channel = getenv(
"ALSA_MIXER_CHANNEL"))) {
267 LOGDEBUG2(
L_SOUND,
"audio: %s: mixer %s - %s open", __FUNCTION__, device, channel);
268 snd_mixer_open(&alsaMixer, 0);
269 if (alsaMixer && snd_mixer_attach(alsaMixer, device) >= 0
270 && snd_mixer_selem_register(alsaMixer, NULL, NULL) >= 0
271 && snd_mixer_load(alsaMixer) >= 0) {
273 const char *
const alsaMixerElem_name = channel;
275 alsaMixerElem = snd_mixer_first_elem(alsaMixer);
276 while (alsaMixerElem) {
279 name = snd_mixer_selem_get_name(alsaMixerElem);
280 if (!strcasecmp(name, alsaMixerElem_name)) {
281 snd_mixer_selem_get_playback_volume_range(alsaMixerElem, &alsaMixerElemMin, &alsaMixerElemMax);
282 m_ratio = 1000 * (alsaMixerElemMax - alsaMixerElemMin);
283 LOGDEBUG2(
L_SOUND,
"audio: %s: %s mixer found %ld - %ld ratio %d", __FUNCTION__, channel, alsaMixerElemMin, alsaMixerElemMax,
m_ratio);
287 alsaMixerElem = snd_mixer_elem_next(alsaMixerElem);
293 LOGERROR(
"audio: %s: can't open mixer '%s'", __FUNCTION__, device);
314 snd_pcm_hw_params_t *hwparams;
315 snd_pcm_hw_params_alloca(&hwparams);
316 if ((err = snd_pcm_hw_params_any(
m_pPCMHandle, hwparams)) < 0) {
317 LOGERROR(
"audio: %s: Read HW config failed (%s)", __FUNCTION__, snd_strerror(err));
322 if (!snd_pcm_hw_params_test_access(
m_pPCMHandle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED))
328 LOGERROR(
"audio: %s: SampleRate %d not supported (%s)", __FUNCTION__, sample_rate, snd_strerror(err));
343 unsigned bufferTimeUs = 100'000;
344 if ((err = snd_pcm_hw_params_set_buffer_time_near(
m_pPCMHandle, hwparams, &bufferTimeUs, NULL)) < 0)
345 LOGWARNING(
"audio: %s: bufferTime %d not supported! %s", __FUNCTION__, bufferTimeUs, snd_strerror(err));
348 if ((err = snd_pcm_set_params(
m_pPCMHandle, SND_PCM_FORMAT_S16,
349 m_useMmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED : SND_PCM_ACCESS_RW_INTERLEAVED,
353 LOGERROR(
"audio: %s: set params error: %s\n"
354 " Requested: Channels %d SampleRate %d\n"
355 " Try to set: HWChannels %d HWSampleRate %d\n"
356 " Format %s , use mmap: %s\n"
357 " AlsaBufferTime %dms pcm state: %s",
358 __FUNCTION__, snd_strerror(err),
359 channels, sample_rate,
361 snd_pcm_format_name(SND_PCM_FORMAT_S16),
m_useMmap ?
"yes" :
"no",
362 bufferTimeUs / 1000, snd_pcm_state_name(state));
367 if ((err = snd_pcm_hw_params_current(
m_pPCMHandle, hwparams)) < 0) {
368 LOGERROR(
"audio: %s: Reading current HW config failed (%s)", __FUNCTION__, snd_strerror(err));
375 snd_pcm_uframes_t periodSize;
376 snd_pcm_uframes_t bufferSize;
377 snd_pcm_get_params(
m_pPCMHandle, &bufferSize, &periodSize);
378 snd_pcm_hw_params_get_buffer_time(hwparams, &bufferTimeUs, 0);
383 std::string channelMapString;
384 for (
size_t i = 0; i < alsaMap.size(); i++) {
385 channelMapString += alsaMap[i];
386 if (i < alsaMap.size() - 1)
387 channelMapString +=
" ";
394 " Requested: Channels %d (%s) SampleRate %d%s\n"
395 " Set: HWChannels %d HWSampleRate %d\n"
396 " Format %s, use mmap: %s\n"
397 " AlsaBufferTime %dms, pcm state: %s\n"
398 " periodSize %d frames, bufferSize %d frames",
400 channels, channelMapString.c_str(), sample_rate, passthrough ?
" -> passthrough" :
" -> PCM",
402 snd_pcm_format_name(SND_PCM_FORMAT_S16),
m_useMmap ?
"yes" :
"no",
403 bufferTimeUs / 1000, snd_pcm_state_name(state),
482 if (state == SND_PCM_STATE_OPEN)
485 LOGDEBUG2(
L_SOUND,
"audio: %s entered in pcm state %s", __FUNCTION__, snd_pcm_state_name(state));
490 case SND_PCM_STATE_SETUP:
491 case SND_PCM_STATE_XRUN:
492 case SND_PCM_STATE_DRAINING:
495 LOGERROR(
"audio: %s: snd_pcm_prepare(): %s", __FUNCTION__, snd_strerror(err));
503 LOGERROR(
"audio: %s: snd_pcm_drop(): %s", __FUNCTION__, snd_strerror(err));
506 LOGERROR(
"audio: %s: snd_pcm_prepare(): %s", __FUNCTION__, snd_strerror(err));
510 LOGDEBUG2(
L_SOUND,
"audio: %s left in pcm state %s", __FUNCTION__, snd_pcm_state_name(state));
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.