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"));
113 err = snd_pcm_open(&
m_pcmHandle, dev_ba.constData(),
114 SND_PCM_STREAM_PLAYBACK, open_mode);
123 VBAUDIO(QString(
"Auto setting passthrough failed (%1), defaulting "
124 "to main device").arg(snd_strerror(err)));
127 if (!try_ac3 || err < 0)
132 err = snd_pcm_open(&
m_pcmHandle, dev_ba.constData(),
133 SND_PCM_STREAM_PLAYBACK, open_mode);
153 snd_pcm_info_t *pcm_info =
nullptr;
155 snd_pcm_info_alloca(&pcm_info);
160 err = snd_pcm_info_get_card(pcm_info);
164 err = snd_pcm_info_get_device(pcm_info);
165 CHECKERR(
"snd_pcm_info_get_device");
168 err = snd_pcm_info_get_subdevice(pcm_info);
169 CHECKERR(
"snd_pcm_info_get_subdevice");
170 int tsubdevice = err;
190 const QString pf = QString(
"/proc/asound/card%1/pcm%2p/sub%3/prealloc")
191 .arg(card).arg(
device).arg(subdevice);
194 QFile mfile(pf +
"_max");
196 if (!pfile.open(QIODevice::ReadOnly))
198 VBERROR(QString(
"Error opening %1. Fix reading permissions.").arg(pf));
202 if (!mfile.open(QIODevice::ReadOnly))
204 VBERROR(QString(
"Error opening %1").arg(pf +
"_max"));
208 int cur = pfile.readAll().trimmed().toInt();
209 int max = mfile.readAll().trimmed().toInt();
211 int size = ((int)(cur * (
float)requested / (float)buffer_time)
214 VBAUDIO(QString(
"Hardware audio buffer cur: %1 need: %2 max allowed: %3")
215 .arg(cur).arg(size).arg(max));
224 if (size > max || !size)
232 VBWARN(QString(
"Try to manually increase audio buffer with: echo %1 "
233 "| sudo tee %2").arg(size).arg(pf));
239 QByteArray *result =
nullptr;
240 snd_hctl_t *hctl =
nullptr;
241 snd_ctl_elem_info_t *info =
nullptr;
242 snd_ctl_elem_id_t *
id =
nullptr;
243 snd_ctl_elem_value_t *
control =
nullptr;
245 snd_ctl_elem_info_alloca(&info);
246 snd_ctl_elem_id_alloca(&
id);
247 snd_ctl_elem_value_alloca(&
control);
249 snd_ctl_elem_id_set_interface(
id, SND_CTL_ELEM_IFACE_PCM);
250 snd_ctl_elem_id_set_name(
id,
"ELD");
251 snd_ctl_elem_id_set_device(
id,
device);
252 snd_ctl_elem_id_set_subdevice(
id, subdevice);
254 int err = snd_hctl_open(&hctl,
255 QString(
"hw:%1").arg(card).toLatin1().constData(),
259 VBAUDIO(QString(
"Control %1 open error: %2")
261 .arg(snd_strerror(err)));
264 if ((err = snd_hctl_load(hctl)) < 0)
266 VBAUDIO(QString(
"Control %1 load error: %2")
268 .arg(snd_strerror(err)));
272 snd_hctl_elem_t *
elem = snd_hctl_find_elem(hctl,
id);
275 err = snd_hctl_elem_info(
elem, info);
278 VBAUDIO(QString(
"Control %1 snd_hctl_elem_info error: %2")
280 .arg(snd_strerror(err)));
281 snd_hctl_close(hctl);
284 unsigned int count = snd_ctl_elem_info_get_count(info);
285 snd_ctl_elem_type_t
type = snd_ctl_elem_info_get_type(info);
286 if (!snd_ctl_elem_info_is_readable(info))
288 VBAUDIO(QString(
"Control %1 element info is not readable")
290 snd_hctl_close(hctl);
295 VBAUDIO(QString(
"Control %1 element read error: %2")
297 .arg(snd_strerror(err)));
298 snd_hctl_close(hctl);
301 if (
type != SND_CTL_ELEM_TYPE_BYTES)
303 VBAUDIO(QString(
"Control %1 element is of the wrong type")
305 snd_hctl_close(hctl);
308 result =
new QByteArray((
char *)snd_ctl_elem_value_get_bytes(
control),
311 snd_hctl_close(hctl);
317 snd_pcm_hw_params_t *params =
nullptr;
318 snd_pcm_format_t afmt = SND_PCM_FORMAT_UNKNOWN;
337 snd_pcm_hw_params_alloca(¶ms);
339 if (snd_pcm_hw_params_any(
m_pcmHandle, params) < 0)
348 if ((err = snd_pcm_hw_params_any(
m_pcmHandle, params)) < 0)
350 AERROR(
"No playback configurations available");
356 Warn(
"Supported audio format detection will be inacurrate "
361 while (
int rate = settings->GetNextRate())
362 if(snd_pcm_hw_params_test_rate(
m_pcmHandle, params, rate, 0) >= 0)
363 settings->AddSupportedRate(rate);
365 while ((fmt = settings->GetNextFormat()))
369 case FORMAT_U8: afmt = SND_PCM_FORMAT_U8;
break;
370 case FORMAT_S16: afmt = SND_PCM_FORMAT_S16;
break;
373 case FORMAT_S24: afmt = SND_PCM_FORMAT_S24;
break;
374 case FORMAT_S32: afmt = SND_PCM_FORMAT_S32;
break;
375 case FORMAT_FLT: afmt = SND_PCM_FORMAT_FLOAT;
break;
378 if (snd_pcm_hw_params_test_format(
m_pcmHandle, params, afmt) >= 0)
379 settings->AddSupportedFormat(fmt);
383 if (snd_pcm_hw_params_test_channels(
m_pcmHandle, params, channels) >= 0)
384 settings->AddSupportedChannels(channels);
395 VBAUDIO(QString(
"Successfully retrieved ELD data"));
396 settings->setELD(
eld);
402 VBAUDIO(
"Can't get card and device number");
410 QMap<QString, QString> *alsadevs =
GetDevices(
"pcm");
416 QString desc = alsadevs->value(real_device);
418 settings->setPassthrough(1);
419 if (real_device.contains(
"digital", Qt::CaseInsensitive) ||
420 desc.contains(
"digital", Qt::CaseInsensitive))
422 if (real_device.contains(
"iec958", Qt::CaseInsensitive))
424 if (real_device.contains(
"spdif", Qt::CaseInsensitive))
426 if (real_device.contains(
"hdmi", Qt::CaseInsensitive))
429 settings->setPassthrough(-1);
431 if (real_device.contains(
"pulse", Qt::CaseInsensitive) ||
432 desc.contains(
"pulse", Qt::CaseInsensitive))
434 if (real_device.contains(
"analog", Qt::CaseInsensitive) ||
435 desc.contains(
"analog", Qt::CaseInsensitive))
437 if (real_device.contains(
"surround", Qt::CaseInsensitive) ||
438 desc.contains(
"surround", Qt::CaseInsensitive))
441 settings->setPassthrough(0);
450 snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN;
466 case FORMAT_U8: format = SND_PCM_FORMAT_U8;
break;
467 case FORMAT_S16: format = SND_PCM_FORMAT_S16;
break;
470 case FORMAT_S24: format = SND_PCM_FORMAT_S24;
break;
471 case FORMAT_S32: format = SND_PCM_FORMAT_S32;
break;
472 case FORMAT_FLT: format = SND_PCM_FORMAT_FLOAT;
break;
481 uint period_time = 4;
484 buffer_time, period_time);
487 AERROR(
"Unable to set ALSA parameters");
493 VBERROR(
"Unable to open audio mixer. Volume control disabled");
502 snd_mixer_close(
m_mixer.handle);
512 template <
class AudioDataType>
517 AudioDataType tmpLFE;
518 AudioDataType *buf2 =
nullptr;
520 for (
uint i = 0; i < frames; i++)
522 buf = buf2 = buf + 2;
547 uchar *tmpbuf = aubuf;
552 Error(
"WriteAudio() called with pcm_handle == nullptr!");
562 LOG(VB_AUDIO | VB_TIMESTAMP, LOG_INFO,
563 QString(
"WriteAudio: Preparing %1 bytes (%2 frames)")
564 .arg(size).arg(frames));
568 int lw = snd_pcm_writei(
m_pcmHandle, tmpbuf, frames);
572 if ((
uint)lw < frames)
573 VBAUDIO(QString(
"WriteAudio: short write %1 bytes (ok)")
586 if (snd_pcm_state(
m_pcmHandle) == SND_PCM_STATE_XRUN)
588 VBAUDIO(
"WriteAudio: buffer underrun");
591 AERROR(
"WriteAudio: unable to recover from xrun");
597 #if ESTRPIPE != EPIPE
599 VBAUDIO(
"WriteAudio: device is suspended");
600 while ((err = snd_pcm_resume(
m_pcmHandle)) == -EAGAIN)
605 VBERROR(
"WriteAudio: resume failed");
608 AERROR(
"WriteAudio: unable to recover from suspend");
617 QString(
"WriteAudio: device is in a bad state (state = %1)")
622 AERROR(QString(
"WriteAudio: Write failed, state: %1, err")
633 VBERROR(
"getBufferedOnSoundcard() called with pcm_handle == nullptr!");
637 snd_pcm_sframes_t delay = 0;
659 snd_pcm_hw_params_t *params =
nullptr;
660 snd_pcm_sw_params_t *swparams =
nullptr;
661 snd_pcm_uframes_t period_size = 0;
662 snd_pcm_uframes_t period_size_min = 0;
663 snd_pcm_uframes_t period_size_max = 0;
664 snd_pcm_uframes_t buffer_size = 0;
665 snd_pcm_uframes_t buffer_size_min = 0;
666 snd_pcm_uframes_t buffer_size_max = 0;
668 VBAUDIO(QString(
"SetParameters(format=%1, channels=%2, rate=%3, "
669 "buffer_time=%4, period_time=%5)")
670 .arg(format).arg(channels).arg(rate).arg(buffer_time)
675 Error(QObject::tr(
"SetParameters() called with handle == nullptr!"));
679 snd_pcm_hw_params_alloca(¶ms);
680 snd_pcm_sw_params_alloca(&swparams);
683 int err = snd_pcm_hw_params_any(
handle, params);
684 CHECKERR(
"No playback configurations available");
687 err = snd_pcm_hw_params_set_access(
handle, params,
688 SND_PCM_ACCESS_RW_INTERLEAVED);
689 CHECKERR(QString(
"Interleaved RW audio not available"));
692 err = snd_pcm_hw_params_set_format(
handle, params, format);
693 CHECKERR(QString(
"Sample format %1 not available").arg(format));
696 err = snd_pcm_hw_params_set_channels(
handle, params, channels);
697 CHECKERR(QString(
"Channels count %1 not available").arg(channels));
702 err = snd_pcm_hw_params_set_rate_resample(
handle, params, 1);
703 CHECKERR(QString(
"Resampling setup failed").arg(rate));
706 err = snd_pcm_hw_params_set_rate_near(
handle, params, &rrate,
nullptr);
707 CHECKERR(QString(
"Rate %1Hz not available for playback: %s").arg(rate));
711 VBERROR(QString(
"Rate doesn't match (requested %1Hz, got %2Hz)")
712 .arg(rate).arg(err));
718 err = snd_pcm_hw_params_set_rate(
handle, params, rate, 0);
719 CHECKERR(QString(
"Samplerate %1 Hz not available").arg(rate));
723 (void) snd_pcm_hw_params_get_buffer_size_min(params, &buffer_size_min);
724 (void) snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size_max);
725 (void) snd_pcm_hw_params_get_period_size_min(params, &period_size_min,
nullptr);
726 (void) snd_pcm_hw_params_get_period_size_max(params, &period_size_max,
nullptr);
727 VBAUDIO(QString(
"Buffer size range from %1 to %2")
728 .arg(buffer_size_min)
729 .arg(buffer_size_max));
730 VBAUDIO(QString(
"Period size range from %1 to %2")
731 .arg(period_size_min)
732 .arg(period_size_max));
735 uint original_buffer_time = buffer_time;
736 bool canincrease =
true;
737 err = snd_pcm_hw_params_set_buffer_time_near(
handle, params,
738 &buffer_time,
nullptr);
742 uint buftmp = buffer_time;
746 err = snd_pcm_hw_params_set_buffer_time_near(
handle, params,
750 AERROR(QString(
"Unable to set buffer time to %1us, retrying")
757 if ((buffer_time <= 100000) ||
758 (attempt > 0 && buffer_time == buftmp))
760 VBERROR(
"Couldn't set buffer time, giving up");
763 buffer_time -= 100000;
773 if (buffer_time * 1.10F < (
float)original_buffer_time)
775 VBWARN(QString(
"Requested %1us got %2 buffer time")
776 .arg(original_buffer_time).arg(buffer_time));
784 VBAUDIO(QString(
"Buffer time = %1 us").arg(buffer_time));
787 err = snd_pcm_hw_params_set_periods_near(
handle, params,
788 &period_time,
nullptr);
789 CHECKERR(QString(
"Unable to set period time %1").arg(period_time));
790 VBAUDIO(QString(
"Period time = %1 periods").arg(period_time));
793 err = snd_pcm_hw_params(
handle, params);
794 CHECKERR(
"Unable to set hw params for playback");
796 err = snd_pcm_get_params(
handle, &buffer_size, &period_size);
797 CHECKERR(
"Unable to get PCM params");
798 VBAUDIO(QString(
"Buffer size = %1 | Period size = %2")
799 .arg(buffer_size).arg(period_size));
806 err = snd_pcm_sw_params_current(
handle, swparams);
807 CHECKERR(
"Unable to get current swparams");
810 err = snd_pcm_sw_params_set_start_threshold(
handle, swparams, period_size);
811 CHECKERR(
"Unable to set start threshold");
814 err = snd_pcm_sw_params_set_avail_min(
handle, swparams, period_size);
815 CHECKERR(
"Unable to set avail min");
818 err = snd_pcm_sw_params(
handle, swparams);
819 CHECKERR(
"Unable to set sw params");
821 err = snd_pcm_prepare(
handle);
822 CHECKERR(
"Unable to prepare the PCM");
834 auto chan = (snd_mixer_selem_channel_id_t) channel;
835 if (!snd_mixer_selem_has_playback_channel(
m_mixer.elem, chan))
839 int chk = snd_mixer_selem_get_playback_volume(
m_mixer.elem, chan,
843 VBERROR(QString(
"failed to get channel %1 volume, mixer %2/%3: %4")
844 .arg(QString::number(channel),
m_mixer.device,
845 m_mixer.control, snd_strerror(chk)));
850 100.0F /
m_mixer.volrange + 0.5F
852 retvol = std::max(retvol, 0);
853 retvol = std::min(retvol, 100);
854 VBAUDIO(QString(
"get volume channel %1: %2")
855 .arg(channel).arg(retvol));
865 long mixervol = (int64_t(volume) *
m_mixer.volrange) / 100 +
m_mixer.volmin;
866 mixervol = std::max(mixervol,
m_mixer.volmin);
867 mixervol = std::min(mixervol,
m_mixer.volmax);
869 auto chan = (snd_mixer_selem_channel_id_t) channel;
871 if (snd_mixer_selem_has_playback_switch(
m_mixer.elem))
872 snd_mixer_selem_set_playback_switch(
m_mixer.elem, chan,
static_cast<int>(volume > 0));
874 if (snd_mixer_selem_set_playback_volume(
m_mixer.elem, chan, mixervol) < 0)
875 VBERROR(QString(
"failed to set channel %1 volume").arg(channel));
877 VBAUDIO(QString(
"channel %1 volume set %2 => %3")
878 .arg(channel).arg(volume).arg(mixervol));
885 VBERROR(
"mixer setup without a pcm");
890 if (
m_mixer.device.toLower() ==
"software")
895 QString mixer_device_tag = QString(
"mixer device %1").arg(
m_mixer.device);
897 int chk = snd_mixer_open(&
m_mixer.handle, 0);
900 VBERROR(QString(
"failed to open mixer device %1: %2")
901 .arg(mixer_device_tag, snd_strerror(chk)));
905 QByteArray dev_ba =
m_mixer.device.toLatin1();
906 struct snd_mixer_selem_regopt regopts =
907 {1, SND_MIXER_SABSTRACT_NONE, dev_ba.constData(),
nullptr,
nullptr};
909 if ((chk = snd_mixer_selem_register(
m_mixer.handle, ®opts,
nullptr)) < 0)
911 snd_mixer_close(
m_mixer.handle);
913 VBERROR(QString(
"failed to register %1: %2")
914 .arg(mixer_device_tag, snd_strerror(chk)));
918 if ((chk = snd_mixer_load(
m_mixer.handle)) < 0)
920 snd_mixer_close(
m_mixer.handle);
922 VBERROR(QString(
"failed to load %1: %2")
923 .arg(mixer_device_tag, snd_strerror(chk)));
928 uint elcount = snd_mixer_get_count(
m_mixer.handle);
929 snd_mixer_elem_t* elx = snd_mixer_first_elem(
m_mixer.handle);
931 for (
uint ctr = 0; elx !=
nullptr && ctr < elcount; ctr++)
933 QString
tmp = QString(snd_mixer_selem_get_name(elx));
935 !snd_mixer_selem_is_enumerated(elx) &&
936 snd_mixer_selem_has_playback_volume(elx) &&
937 snd_mixer_selem_is_active(elx))
940 VBAUDIO(QString(
"found playback control %1 on %2")
941 .arg(
m_mixer.control, mixer_device_tag));
944 elx = snd_mixer_elem_next(elx);
948 snd_mixer_close(
m_mixer.handle);
950 VBERROR(QString(
"no playback control %1 found on %2")
951 .arg(
m_mixer.control, mixer_device_tag));
954 if ((snd_mixer_selem_get_playback_volume_range(
m_mixer.elem,
958 snd_mixer_close(
m_mixer.handle);
960 VBERROR(QString(
"failed to get volume range on %1/%2")
961 .arg(mixer_device_tag,
m_mixer.control));
966 VBAUDIO(QString(
"mixer volume range on %1/%2 - min %3, max %4, range %5")
967 .arg(mixer_device_tag,
m_mixer.control)
969 VBAUDIO(QString(
"%1/%2 set up successfully")
970 .arg(mixer_device_tag,
m_mixer.control));
974 int initial_vol = 80;
988 auto *alsadevs =
new QMap<QString, QString>();
989 void **hints =
nullptr;
992 if (snd_device_name_hint(-1,
type, &hints) < 0)
996 while (*n !=
nullptr)
998 QString name = snd_device_name_get_hint(*n,
"NAME");
999 QString desc = snd_device_name_get_hint(*n,
"DESC");
1000 if (!name.isEmpty() && !desc.isEmpty() && (name !=
"null"))
1001 alsadevs->insert(name, desc);
1004 snd_device_name_free_hint(hints);
1007 #if SND_LIB_MAJOR == 1
1008 #if SND_LIB_MINOR == 0
1009 #if SND_LIB_SUBMINOR < 22
1010 snd_config_update_free_global();