11 #define LOC QString("ALSA: ")
22 { SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_FORMAT | SND_PCM_NO_AUTO_CHANNELS };
27 #define AERROR(str) VBERROR((str) + QString(": %1").arg(snd_strerror(err)))
28 #define CHECKERR(str) { if (err < 0) { AERROR(str); return err; } }
51 QString iecarg = QString(
"AES0=6,AES1=0x82,AES2=0x00") +
52 (s48k ? QString() : QString(
",AES3=0x01"));
53 QString iecarg2 = QString(
"AES0=6 AES1=0x82 AES2=0x00") +
54 (s48k ? QString() : QString(
" AES3=0x01"));
117 err = snd_pcm_open(&
m_pcmHandle, dev_ba.constData(),
118 SND_PCM_STREAM_PLAYBACK, open_mode);
127 VBAUDIO(QString(
"Auto setting passthrough failed (%1), defaulting "
128 "to main device").arg(snd_strerror(err)));
131 if (!try_ac3 || err < 0)
136 err = snd_pcm_open(&
m_pcmHandle, dev_ba.constData(),
137 SND_PCM_STREAM_PLAYBACK, open_mode);
157 snd_pcm_info_t *pcm_info =
nullptr;
159 snd_pcm_info_alloca(&pcm_info);
164 err = snd_pcm_info_get_card(pcm_info);
168 err = snd_pcm_info_get_device(pcm_info);
169 CHECKERR(
"snd_pcm_info_get_device");
172 err = snd_pcm_info_get_subdevice(pcm_info);
173 CHECKERR(
"snd_pcm_info_get_subdevice");
174 int tsubdevice = err;
194 const QString pf = QString(
"/proc/asound/card%1/pcm%2p/sub%3/prealloc")
195 .arg(card).arg(
device).arg(subdevice);
198 QFile mfile(pf +
"_max");
200 if (!pfile.open(QIODevice::ReadOnly))
202 VBERROR(QString(
"Error opening %1. Fix reading permissions.").arg(pf));
206 if (!mfile.open(QIODevice::ReadOnly))
208 VBERROR(QString(
"Error opening %1").arg(pf +
"_max"));
212 int cur = pfile.readAll().trimmed().toInt();
213 int max = mfile.readAll().trimmed().toInt();
215 int size = ((int)(cur * (
float)requested / (float)buffer_time)
218 VBAUDIO(QString(
"Hardware audio buffer cur: %1 need: %2 max allowed: %3")
219 .arg(cur).arg(size).arg(max));
228 if (size > max || !size)
236 VBWARN(QString(
"Try to manually increase audio buffer with: echo %1 "
237 "| sudo tee %2").arg(size).arg(pf));
243 QByteArray *result =
nullptr;
244 snd_hctl_t *hctl =
nullptr;
245 snd_ctl_elem_info_t *
info =
nullptr;
246 snd_ctl_elem_id_t *
id =
nullptr;
247 snd_ctl_elem_value_t *
control =
nullptr;
249 snd_ctl_elem_info_alloca(&
info);
250 snd_ctl_elem_id_alloca(&
id);
251 snd_ctl_elem_value_alloca(&
control);
253 snd_ctl_elem_id_set_interface(
id, SND_CTL_ELEM_IFACE_PCM);
254 snd_ctl_elem_id_set_name(
id,
"ELD");
255 snd_ctl_elem_id_set_device(
id,
device);
256 snd_ctl_elem_id_set_subdevice(
id, subdevice);
258 int err = snd_hctl_open(&hctl,
259 QString(
"hw:%1").arg(card).toLatin1().constData(),
263 VBAUDIO(QString(
"Control %1 open error: %2")
265 .arg(snd_strerror(err)));
268 err = snd_hctl_load(hctl);
271 VBAUDIO(QString(
"Control %1 load error: %2")
273 .arg(snd_strerror(err)));
277 snd_hctl_elem_t *
elem = snd_hctl_find_elem(hctl,
id);
280 err = snd_hctl_elem_info(
elem,
info);
283 VBAUDIO(QString(
"Control %1 snd_hctl_elem_info error: %2")
285 .arg(snd_strerror(err)));
286 snd_hctl_close(hctl);
289 unsigned int count = snd_ctl_elem_info_get_count(
info);
290 snd_ctl_elem_type_t
type = snd_ctl_elem_info_get_type(
info);
291 if (!snd_ctl_elem_info_is_readable(
info))
293 VBAUDIO(QString(
"Control %1 element info is not readable")
295 snd_hctl_close(hctl);
301 VBAUDIO(QString(
"Control %1 element read error: %2")
303 .arg(snd_strerror(err)));
304 snd_hctl_close(hctl);
307 if (
type != SND_CTL_ELEM_TYPE_BYTES)
309 VBAUDIO(QString(
"Control %1 element is of the wrong type")
311 snd_hctl_close(hctl);
314 result =
new QByteArray((
char *)snd_ctl_elem_value_get_bytes(
control),
317 snd_hctl_close(hctl);
323 snd_pcm_hw_params_t *params =
nullptr;
324 snd_pcm_format_t afmt = SND_PCM_FORMAT_UNKNOWN;
343 snd_pcm_hw_params_alloca(¶ms);
345 if (snd_pcm_hw_params_any(
m_pcmHandle, params) < 0)
358 AERROR(
"No playback configurations available");
364 Warn(
"Supported audio format detection will be inacurrate "
369 while (
int rate = settings->GetNextRate())
370 if(snd_pcm_hw_params_test_rate(
m_pcmHandle, params, rate, 0) >= 0)
371 settings->AddSupportedRate(rate);
373 while ((fmt = settings->GetNextFormat()))
377 case FORMAT_U8: afmt = SND_PCM_FORMAT_U8;
break;
378 case FORMAT_S16: afmt = SND_PCM_FORMAT_S16;
break;
381 case FORMAT_S24: afmt = SND_PCM_FORMAT_S24;
break;
382 case FORMAT_S32: afmt = SND_PCM_FORMAT_S32;
break;
383 case FORMAT_FLT: afmt = SND_PCM_FORMAT_FLOAT;
break;
386 if (snd_pcm_hw_params_test_format(
m_pcmHandle, params, afmt) >= 0)
387 settings->AddSupportedFormat(fmt);
391 if (snd_pcm_hw_params_test_channels(
m_pcmHandle, params, channels) >= 0)
392 settings->AddSupportedChannels(channels);
403 VBAUDIO(QString(
"Successfully retrieved ELD data"));
404 settings->setELD(
eld);
410 VBAUDIO(
"Can't get card and device number");
418 QMap<QString, QString> *alsadevs =
GetDevices(
"pcm");
424 QString desc = alsadevs->value(real_device);
426 settings->setPassthrough(1);
427 if (real_device.contains(
"digital", Qt::CaseInsensitive) ||
428 desc.contains(
"digital", Qt::CaseInsensitive))
430 if (real_device.contains(
"iec958", Qt::CaseInsensitive))
432 if (real_device.contains(
"spdif", Qt::CaseInsensitive))
434 if (real_device.contains(
"hdmi", Qt::CaseInsensitive))
437 settings->setPassthrough(-1);
439 if (real_device.contains(
"pulse", Qt::CaseInsensitive) ||
440 desc.contains(
"pulse", Qt::CaseInsensitive))
442 if (real_device.contains(
"analog", Qt::CaseInsensitive) ||
443 desc.contains(
"analog", Qt::CaseInsensitive))
445 if (real_device.contains(
"surround", Qt::CaseInsensitive) ||
446 desc.contains(
"surround", Qt::CaseInsensitive))
449 settings->setPassthrough(0);
458 snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
474 case FORMAT_U8: format = SND_PCM_FORMAT_U8;
break;
475 case FORMAT_S16: format = SND_PCM_FORMAT_S16;
break;
478 case FORMAT_S24: format = SND_PCM_FORMAT_S24;
break;
479 case FORMAT_S32: format = SND_PCM_FORMAT_S32;
break;
480 case FORMAT_FLT: format = SND_PCM_FORMAT_FLOAT;
break;
489 uint period_time = 4;
492 buffer_time, period_time);
495 AERROR(
"Unable to set ALSA parameters");
501 VBERROR(
"Unable to open audio mixer. Volume control disabled");
510 snd_mixer_close(
m_mixer.handle);
520 template <
class AudioDataType>
525 AudioDataType tmpLFE;
526 AudioDataType *buf2 =
nullptr;
528 for (
uint i = 0; i < frames; i++)
530 buf = buf2 = buf + 2;
555 uchar *tmpbuf = aubuf;
560 Error(
"WriteAudio() called with pcm_handle == nullptr!");
570 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO,
571 QString(
"WriteAudio: Preparing %1 bytes (%2 frames)")
572 .arg(size).arg(frames));
576 int lw = snd_pcm_writei(
m_pcmHandle, tmpbuf, frames);
580 if ((
uint)lw < frames)
581 VBAUDIO(QString(
"WriteAudio: short write %1 bytes (ok)")
594 if (snd_pcm_state(
m_pcmHandle) == SND_PCM_STATE_XRUN)
596 VBAUDIO(
"WriteAudio: buffer underrun");
600 AERROR(
"WriteAudio: unable to recover from xrun");
606 #if ESTRPIPE != EPIPE
608 VBAUDIO(
"WriteAudio: device is suspended");
609 while ((err = snd_pcm_resume(
m_pcmHandle)) == -EAGAIN)
614 VBERROR(
"WriteAudio: resume failed");
618 AERROR(
"WriteAudio: unable to recover from suspend");
627 QString(
"WriteAudio: device is in a bad state (state = %1)")
632 AERROR(QString(
"WriteAudio: Write failed, state: %1, err")
643 VBERROR(
"getBufferedOnSoundcard() called with pcm_handle == nullptr!");
647 snd_pcm_sframes_t delay = 0;
669 snd_pcm_hw_params_t *params =
nullptr;
670 snd_pcm_sw_params_t *swparams =
nullptr;
671 snd_pcm_uframes_t period_size = 0;
672 snd_pcm_uframes_t period_size_min = 0;
673 snd_pcm_uframes_t period_size_max = 0;
674 snd_pcm_uframes_t buffer_size = 0;
675 snd_pcm_uframes_t buffer_size_min = 0;
676 snd_pcm_uframes_t buffer_size_max = 0;
678 VBAUDIO(QString(
"SetParameters(format=%1, channels=%2, rate=%3, "
679 "buffer_time=%4, period_time=%5)")
680 .arg(format).arg(channels).arg(rate).arg(buffer_time)
685 Error(QObject::tr(
"SetParameters() called with handle == nullptr!"));
689 snd_pcm_hw_params_alloca(¶ms);
690 snd_pcm_sw_params_alloca(&swparams);
693 int err = snd_pcm_hw_params_any(
handle, params);
694 CHECKERR(
"No playback configurations available");
697 err = snd_pcm_hw_params_set_access(
handle, params,
698 SND_PCM_ACCESS_RW_INTERLEAVED);
699 CHECKERR(QString(
"Interleaved RW audio not available"));
702 err = snd_pcm_hw_params_set_format(
handle, params, format);
703 CHECKERR(QString(
"Sample format %1 not available").arg(format));
706 err = snd_pcm_hw_params_set_channels(
handle, params, channels);
707 CHECKERR(QString(
"Channels count %1 not available").arg(channels));
712 err = snd_pcm_hw_params_set_rate_resample(
handle, params, 1);
713 CHECKERR(QString(
"Resampling setup failed").arg(rate));
716 err = snd_pcm_hw_params_set_rate_near(
handle, params, &rrate,
nullptr);
717 CHECKERR(QString(
"Rate %1Hz not available for playback: %s").arg(rate));
721 VBERROR(QString(
"Rate doesn't match (requested %1Hz, got %2Hz)")
722 .arg(rate).arg(err));
728 err = snd_pcm_hw_params_set_rate(
handle, params, rate, 0);
729 CHECKERR(QString(
"Samplerate %1 Hz not available").arg(rate));
733 (void) snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min);
734 (void) snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max);
735 (void) snd_pcm_hw_params_get_period_size_min(params, &period_size_min,
nullptr);
736 (void) snd_pcm_hw_params_get_period_size_max(params, &period_size_max,
nullptr);
737 VBAUDIO(QString(
"Buffer size range from %1 to %2")
738 .arg(buffer_size_min)
739 .arg(buffer_size_max));
740 VBAUDIO(QString(
"Period size range from %1 to %2")
741 .arg(period_size_min)
742 .arg(period_size_max));
745 uint original_buffer_time = buffer_time;
746 bool canincrease =
true;
747 err = snd_pcm_hw_params_set_buffer_time_near(
handle, params,
748 &buffer_time,
nullptr);
752 uint buftmp = buffer_time;
756 err = snd_pcm_hw_params_set_buffer_time_near(
handle, params,
760 AERROR(QString(
"Unable to set buffer time to %1us, retrying")
767 if ((buffer_time <= 100000) ||
768 (attempt > 0 && buffer_time == buftmp))
770 VBERROR(
"Couldn't set buffer time, giving up");
773 buffer_time -= 100000;
783 if (buffer_time * 1.10F < (
float)original_buffer_time)
785 VBWARN(QString(
"Requested %1us got %2 buffer time")
786 .arg(original_buffer_time).arg(buffer_time));
794 VBAUDIO(QString(
"Buffer time = %1 us").arg(buffer_time));
797 err = snd_pcm_hw_params_set_periods_near(
handle, params,
798 &period_time,
nullptr);
799 CHECKERR(QString(
"Unable to set period time %1").arg(period_time));
800 VBAUDIO(QString(
"Period time = %1 periods").arg(period_time));
803 err = snd_pcm_hw_params(
handle, params);
804 CHECKERR(
"Unable to set hw params for playback");
806 err = snd_pcm_get_params(
handle, &buffer_size, &period_size);
807 CHECKERR(
"Unable to get PCM params");
808 VBAUDIO(QString(
"Buffer size = %1 | Period size = %2")
809 .arg(buffer_size).arg(period_size));
816 err = snd_pcm_sw_params_current(
handle, swparams);
817 CHECKERR(
"Unable to get current swparams");
820 err = snd_pcm_sw_params_set_start_threshold(
handle, swparams, period_size);
821 CHECKERR(
"Unable to set start threshold");
824 err = snd_pcm_sw_params_set_avail_min(
handle, swparams, period_size);
825 CHECKERR(
"Unable to set avail min");
828 err = snd_pcm_sw_params(
handle, swparams);
829 CHECKERR(
"Unable to set sw params");
831 err = snd_pcm_prepare(
handle);
832 CHECKERR(
"Unable to prepare the PCM");
844 auto chan = (snd_mixer_selem_channel_id_t) channel;
845 if (!snd_mixer_selem_has_playback_channel(
m_mixer.elem, chan))
849 int chk = snd_mixer_selem_get_playback_volume(
m_mixer.elem, chan,
853 VBERROR(QString(
"failed to get channel %1 volume, mixer %2/%3: %4")
854 .arg(QString::number(channel),
m_mixer.device,
855 m_mixer.control, snd_strerror(chk)));
859 retvol = (
m_mixer.volrange != 0L)
860 ? ((mixervol -
m_mixer.volmin) * 100.0F /
m_mixer.volrange) + 0.5F
862 retvol = std::max(retvol, 0);
863 retvol = std::min(retvol, 100);
864 VBAUDIO(QString(
"get volume channel %1: %2")
865 .arg(channel).arg(retvol));
875 long mixervol = ((int64_t(volume) *
m_mixer.volrange) / 100) +
m_mixer.volmin;
876 mixervol = std::max(mixervol,
m_mixer.volmin);
877 mixervol = std::min(mixervol,
m_mixer.volmax);
879 auto chan = (snd_mixer_selem_channel_id_t) channel;
881 if (snd_mixer_selem_has_playback_switch(
m_mixer.elem))
882 snd_mixer_selem_set_playback_switch(
m_mixer.elem, chan,
static_cast<int>(volume > 0));
884 if (snd_mixer_selem_set_playback_volume(
m_mixer.elem, chan, mixervol) < 0)
885 VBERROR(QString(
"failed to set channel %1 volume").arg(channel));
887 VBAUDIO(QString(
"channel %1 volume set %2 => %3")
888 .arg(channel).arg(volume).arg(mixervol));
895 VBERROR(
"mixer setup without a pcm");
900 if (
m_mixer.device.toLower() ==
"software")
905 QString mixer_device_tag = QString(
"mixer device %1").arg(
m_mixer.device);
907 int chk = snd_mixer_open(&
m_mixer.handle, 0);
910 VBERROR(QString(
"failed to open mixer device %1: %2")
911 .arg(mixer_device_tag, snd_strerror(chk)));
915 QByteArray dev_ba =
m_mixer.device.toLatin1();
916 struct snd_mixer_selem_regopt regopts =
917 {1, SND_MIXER_SABSTRACT_NONE, dev_ba.constData(),
nullptr,
nullptr};
919 chk = snd_mixer_selem_register(
m_mixer.handle, ®opts,
nullptr);
922 snd_mixer_close(
m_mixer.handle);
924 VBERROR(QString(
"failed to register %1: %2")
925 .arg(mixer_device_tag, snd_strerror(chk)));
929 chk = snd_mixer_load(
m_mixer.handle);
932 snd_mixer_close(
m_mixer.handle);
934 VBERROR(QString(
"failed to load %1: %2")
935 .arg(mixer_device_tag, snd_strerror(chk)));
940 uint elcount = snd_mixer_get_count(
m_mixer.handle);
941 snd_mixer_elem_t* elx = snd_mixer_first_elem(
m_mixer.handle);
943 for (
uint ctr = 0; elx !=
nullptr && ctr < elcount; ctr++)
945 QString
tmp = QString(snd_mixer_selem_get_name(elx));
947 !snd_mixer_selem_is_enumerated(elx) &&
948 snd_mixer_selem_has_playback_volume(elx) &&
949 snd_mixer_selem_is_active(elx))
952 VBAUDIO(QString(
"found playback control %1 on %2")
953 .arg(
m_mixer.control, mixer_device_tag));
956 elx = snd_mixer_elem_next(elx);
960 snd_mixer_close(
m_mixer.handle);
962 VBERROR(QString(
"no playback control %1 found on %2")
963 .arg(
m_mixer.control, mixer_device_tag));
966 if ((snd_mixer_selem_get_playback_volume_range(
m_mixer.elem,
970 snd_mixer_close(
m_mixer.handle);
972 VBERROR(QString(
"failed to get volume range on %1/%2")
973 .arg(mixer_device_tag,
m_mixer.control));
978 VBAUDIO(QString(
"mixer volume range on %1/%2 - min %3, max %4, range %5")
979 .arg(mixer_device_tag,
m_mixer.control)
981 VBAUDIO(QString(
"%1/%2 set up successfully")
982 .arg(mixer_device_tag,
m_mixer.control));
986 int initial_vol = 80;
1000 auto *alsadevs =
new QMap<QString, QString>();
1001 void **hints =
nullptr;
1004 if (snd_device_name_hint(-1,
type, &hints) < 0)
1008 while (*n !=
nullptr)
1010 QString name = snd_device_name_get_hint(*n,
"NAME");
1011 QString desc = snd_device_name_get_hint(*n,
"DESC");
1012 if (!name.isEmpty() && !desc.isEmpty() && (name !=
"null"))
1013 alsadevs->insert(name, desc);
1016 snd_device_name_free_hint(hints);
1019 #if SND_LIB_MAJOR == 1
1020 #if SND_LIB_MINOR == 0
1021 #if SND_LIB_SUBMINOR < 22
1022 snd_config_update_free_global();