2 * Copyright (C) 2010-2013 Team XBMC
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, or (at your option)
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.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
28 #include "AESinkALSA.h"
29 #include "cores/AudioEngine/Utils/AEUtil.h"
30 #include "cores/AudioEngine/Utils/AEELDParser.h"
31 #include "utils/StdString.h"
32 #include "utils/log.h"
33 #include "utils/MathUtils.h"
34 #include "threads/SingleLock.h"
35 #if defined(HAS_LIBAMCODEC)
36 #include "utils/AMLUtils.h"
39 #define ALSA_OPTIONS (SND_PCM_NO_AUTO_FORMAT | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_RESAMPLE)
41 #define ALSA_MAX_CHANNELS 16
42 static enum AEChannel ALSAChannelMap[ALSA_MAX_CHANNELS + 1] = {
43 AE_CH_FL , AE_CH_FR , AE_CH_BL , AE_CH_BR , AE_CH_FC , AE_CH_LFE , AE_CH_SL , AE_CH_SR ,
44 AE_CH_UNKNOWN1, AE_CH_UNKNOWN2, AE_CH_UNKNOWN3, AE_CH_UNKNOWN4, AE_CH_UNKNOWN5, AE_CH_UNKNOWN6, AE_CH_UNKNOWN7, AE_CH_UNKNOWN8, /* for p16v devices */
48 static enum AEChannel ALSAChannelMap51Wide[ALSA_MAX_CHANNELS + 1] = {
49 AE_CH_FL , AE_CH_FR , AE_CH_SL , AE_CH_SR , AE_CH_FC , AE_CH_LFE , AE_CH_BL , AE_CH_BR ,
50 AE_CH_UNKNOWN1, AE_CH_UNKNOWN2, AE_CH_UNKNOWN3, AE_CH_UNKNOWN4, AE_CH_UNKNOWN5, AE_CH_UNKNOWN6, AE_CH_UNKNOWN7, AE_CH_UNKNOWN8, /* for p16v devices */
54 static enum AEChannel ALSAChannelMapPassthrough[ALSA_MAX_CHANNELS + 1] = {
55 AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW , AE_CH_RAW ,
56 AE_CH_UNKNOWN1, AE_CH_UNKNOWN2, AE_CH_UNKNOWN3, AE_CH_UNKNOWN4, AE_CH_UNKNOWN5, AE_CH_UNKNOWN6, AE_CH_UNKNOWN7, AE_CH_UNKNOWN8, /* for p16v devices */
60 static unsigned int ALSASampleRateList[] =
79 CAESinkALSA::CAESinkALSA() :
81 m_formatSampleRateMul(0.0),
86 /* ensure that ALSA has been initialized */
91 CAESinkALSA::~CAESinkALSA()
96 inline CAEChannelInfo CAESinkALSA::GetChannelLayout(AEAudioFormat format, unsigned int minChannels, unsigned int maxChannels)
98 enum AEChannel* channelMap = ALSAChannelMap;
99 unsigned int count = 0;
101 if (format.m_dataFormat == AE_FMT_AC3 ||
102 format.m_dataFormat == AE_FMT_DTS ||
103 format.m_dataFormat == AE_FMT_EAC3)
106 channelMap = ALSAChannelMapPassthrough;
108 else if (format.m_dataFormat == AE_FMT_TRUEHD ||
109 format.m_dataFormat == AE_FMT_DTSHD)
112 channelMap = ALSAChannelMapPassthrough;
116 // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
117 // but no BR BL channels, we use the wide map in order to open only the num of channels really
119 if (format.m_channelLayout.HasChannel(AE_CH_SL) && !format.m_channelLayout.HasChannel(AE_CH_BL))
121 channelMap = ALSAChannelMap51Wide;
123 for (unsigned int c = 0; c < 8; ++c)
125 for (unsigned int i = 0; i < format.m_channelLayout.Count(); ++i)
127 if (format.m_channelLayout[i] == channelMap[c])
134 count = std::max(count, minChannels);
138 count = std::min(count, maxChannels);
139 for (unsigned int i = 0; i < count; ++i)
140 info += channelMap[i];
142 CLog::Log(LOGDEBUG, "CAESinkALSA::GetChannelLayout - Input Channel Count: %d Output Channel Count: %d", format.m_channelLayout.Count(), count);
143 CLog::Log(LOGDEBUG, "CAESinkALSA::GetChannelLayout - Requested Layout: %s", std::string(format.m_channelLayout).c_str());
144 CLog::Log(LOGDEBUG, "CAESinkALSA::GetChannelLayout - Got Layout: %s", std::string(info).c_str());
149 void CAESinkALSA::GetAESParams(AEAudioFormat format, std::string& params)
152 params = "AES0=0x06";
154 params = "AES0=0x04";
156 params += ",AES1=0x82,AES2=0x00";
158 if (format.m_sampleRate == 192000) params += ",AES3=0x0e";
159 else if (format.m_sampleRate == 176400) params += ",AES3=0x0c";
160 else if (format.m_sampleRate == 96000) params += ",AES3=0x0a";
161 else if (format.m_sampleRate == 88200) params += ",AES3=0x08";
162 else if (format.m_sampleRate == 48000) params += ",AES3=0x02";
163 else if (format.m_sampleRate == 44100) params += ",AES3=0x00";
164 else if (format.m_sampleRate == 32000) params += ",AES3=0x03";
165 else params += ",AES3=0x01";
168 bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
170 CAEChannelInfo channelLayout = GetChannelLayout(format, 2, 8);
171 m_initDevice = device;
172 m_initFormat = format;
173 ALSAConfig inconfig, outconfig;
174 inconfig.format = format.m_dataFormat;
175 inconfig.sampleRate = format.m_sampleRate;
176 inconfig.channels = channelLayout.Count();
178 /* if we are raw, correct the data format */
179 if (AE_IS_RAW(format.m_dataFormat))
181 inconfig.format = AE_FMT_S16NE;
182 m_passthrough = true;
186 m_passthrough = false;
188 #if defined(HAS_LIBAMCODEC)
191 aml_set_audio_passthrough(m_passthrough);
196 if (inconfig.channels == 0)
198 CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout");
202 AEDeviceType devType = AEDeviceTypeFromName(device);
204 std::string AESParams;
205 /* digital interfaces should have AESx set, though in practice most
206 * receivers don't care */
207 if (m_passthrough || devType == AE_DEVTYPE_HDMI || devType == AE_DEVTYPE_IEC958)
208 GetAESParams(format, AESParams);
210 CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Attempting to open device \"%s\"", device.c_str());
212 /* get the sound config */
213 snd_config_t *config;
214 snd_config_copy(&config, snd_config);
216 if (!OpenPCMDevice(device, AESParams, inconfig.channels, &m_pcm, config))
218 CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str());
219 snd_config_delete(config);
223 /* get the actual device name that was used */
224 device = snd_pcm_name(m_pcm);
227 CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Opened device \"%s\"", device.c_str());
229 /* free the sound config */
230 snd_config_delete(config);
232 if (!InitializeHW(inconfig, outconfig) || !InitializeSW(outconfig))
235 // we want it blocking
236 snd_pcm_nonblock(m_pcm, 0);
237 snd_pcm_prepare (m_pcm);
239 if (m_passthrough && inconfig.channels != outconfig.channels)
241 CLog::Log(LOGINFO, "CAESinkALSA::Initialize - could not open required number of channels");
244 // adjust format to the configuration we got
245 format.m_channelLayout = GetChannelLayout(format, outconfig.channels, outconfig.channels);
246 format.m_sampleRate = outconfig.sampleRate;
247 format.m_frames = outconfig.periodSize;
248 format.m_frameSize = outconfig.frameSize;
249 format.m_frameSamples = outconfig.periodSize * outconfig.channels;
250 format.m_dataFormat = outconfig.format;
253 m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate;
258 snd_pcm_format_t CAESinkALSA::AEFormatToALSAFormat(const enum AEDataFormat format)
260 if (AE_IS_RAW(format))
261 return SND_PCM_FORMAT_S16;
265 case AE_FMT_S8 : return SND_PCM_FORMAT_S8;
266 case AE_FMT_U8 : return SND_PCM_FORMAT_U8;
267 case AE_FMT_S16NE : return SND_PCM_FORMAT_S16;
268 case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE;
269 case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE;
270 case AE_FMT_S24NE4: return SND_PCM_FORMAT_S24;
271 #ifdef __BIG_ENDIAN__
272 case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE;
274 case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3LE;
276 case AE_FMT_S32NE : return SND_PCM_FORMAT_S32;
277 case AE_FMT_FLOAT : return SND_PCM_FORMAT_FLOAT;
280 return SND_PCM_FORMAT_UNKNOWN;
284 bool CAESinkALSA::InitializeHW(const ALSAConfig &inconfig, ALSAConfig &outconfig)
286 snd_pcm_hw_params_t *hw_params;
288 snd_pcm_hw_params_alloca(&hw_params);
289 memset(hw_params, 0, snd_pcm_hw_params_sizeof());
291 snd_pcm_hw_params_any(m_pcm, hw_params);
292 snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
294 unsigned int sampleRate = inconfig.sampleRate;
295 unsigned int channelCount = inconfig.channels;
296 snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL);
297 snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount);
299 /* ensure we opened X channels or more */
300 if (inconfig.channels > channelCount)
302 CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Unable to open the required number of channels");
305 /* update outconfig */
306 outconfig.channels = channelCount;
308 snd_pcm_format_t fmt = AEFormatToALSAFormat(inconfig.format);
309 outconfig.format = inconfig.format;
311 if (fmt == SND_PCM_FORMAT_UNKNOWN)
313 /* if we dont support the requested format, fallback to float */
314 fmt = SND_PCM_FORMAT_FLOAT;
315 outconfig.format = AE_FMT_FLOAT;
318 /* try the data format */
319 if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
321 /* if the chosen format is not supported, try each one in decending order */
322 CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(outconfig.format));
323 for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
325 if (AE_IS_RAW(i) || i == AE_FMT_MAX)
328 if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE)
331 fmt = AEFormatToALSAFormat(i);
333 if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
335 fmt = SND_PCM_FORMAT_UNKNOWN;
339 int fmtBits = CAEUtil::DataFormatToBits(i);
340 int bits = snd_pcm_hw_params_get_sbits(hw_params);
343 /* if we opened in 32bit and only have 24bits, pack into 24 */
344 if (fmtBits == 32 && bits == 24)
350 /* record that the format fell back to X */
351 outconfig.format = i;
352 CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(outconfig.format));
356 /* if we failed to find a valid output format */
357 if (fmt == SND_PCM_FORMAT_UNKNOWN)
359 CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format");
364 snd_pcm_uframes_t periodSize, bufferSize;
365 snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize);
366 snd_pcm_hw_params_get_period_size_max(hw_params, &periodSize, NULL);
369 We want to make sure, that we have max 200 ms Buffer with
370 a periodSize of approx 50 ms. Choosing a higher bufferSize
371 will cause problems with menu sounds. Buffer will be increased
372 after those are fixed.
374 periodSize = std::min(periodSize, (snd_pcm_uframes_t) sampleRate / 20);
375 bufferSize = std::min(bufferSize, (snd_pcm_uframes_t) sampleRate / 5);
378 According to upstream we should set buffer size first - so make sure it is always at least
379 4x period size to not get underruns (some systems seem to have issues with only 2 periods)
381 periodSize = std::min(periodSize, bufferSize / 4);
383 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
385 snd_pcm_hw_params_t *hw_params_copy;
386 snd_pcm_hw_params_alloca(&hw_params_copy);
387 snd_pcm_hw_params_copy(hw_params_copy, hw_params); // copy what we have and is already working
389 // Make sure to not initialize too large to not cause underruns
390 snd_pcm_uframes_t periodSizeMax = bufferSize / 3;
391 if(snd_pcm_hw_params_set_period_size_max(m_pcm, hw_params_copy, &periodSizeMax, NULL) != 0)
393 snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
394 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: Failed to limit periodSize to %lu", periodSizeMax);
397 // first trying bufferSize, PeriodSize
398 // for more info see here:
399 // http://mailman.alsa-project.org/pipermail/alsa-devel/2009-September/021069.html
400 // the last three tries are done as within pulseaudio
402 // backup periodSize and bufferSize first. Restore them after every failed try
403 snd_pcm_uframes_t periodSizeTemp, bufferSizeTemp;
404 periodSizeTemp = periodSize;
405 bufferSizeTemp = bufferSize;
406 if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
407 || snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
408 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
410 bufferSize = bufferSizeTemp;
411 periodSize = periodSizeTemp;
412 // retry with PeriodSize, bufferSize
413 snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
414 if (snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
415 || snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
416 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
418 // try only periodSize
419 periodSize = periodSizeTemp;
420 snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
421 if(snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
422 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
424 // try only BufferSize
425 bufferSize = bufferSizeTemp;
426 snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restory working copy
427 if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
428 || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
430 // set default that Alsa would choose
431 CLog::Log(LOGWARNING, "CAESinkAlsa::IntializeHW - Using default alsa values - set failed");
432 if (snd_pcm_hw_params(m_pcm, hw_params) != 0)
434 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Could not init a valid sink");
439 // reread values when alsa default was kept
440 snd_pcm_get_params(m_pcm, &bufferSize, &periodSize);
444 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
446 /* set the format parameters */
447 outconfig.sampleRate = sampleRate;
448 outconfig.periodSize = periodSize;
449 outconfig.frameSize = snd_pcm_frames_to_bytes(m_pcm, 1);
451 m_bufferSize = (unsigned int)bufferSize;
452 m_timeout = std::ceil((double)(bufferSize * 1000) / (double)sampleRate);
454 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout);
459 bool CAESinkALSA::InitializeSW(const ALSAConfig &inconfig)
461 snd_pcm_sw_params_t *sw_params;
462 snd_pcm_uframes_t boundary;
464 snd_pcm_sw_params_alloca(&sw_params);
465 memset(sw_params, 0, snd_pcm_sw_params_sizeof());
467 snd_pcm_sw_params_current (m_pcm, sw_params);
468 snd_pcm_sw_params_set_start_threshold (m_pcm, sw_params, INT_MAX);
469 snd_pcm_sw_params_set_silence_threshold(m_pcm, sw_params, 0);
470 snd_pcm_sw_params_get_boundary (sw_params, &boundary);
471 snd_pcm_sw_params_set_silence_size (m_pcm, sw_params, boundary);
472 snd_pcm_sw_params_set_avail_min (m_pcm, sw_params, inconfig.periodSize);
474 if (snd_pcm_sw_params(m_pcm, sw_params) < 0)
476 CLog::Log(LOGERROR, "CAESinkALSA::InitializeSW - Failed to set the parameters");
483 void CAESinkALSA::Deinitialize()
488 snd_pcm_close(m_pcm);
493 void CAESinkALSA::Stop()
500 double CAESinkALSA::GetDelay()
504 snd_pcm_sframes_t frames = 0;
505 snd_pcm_delay(m_pcm, &frames);
509 #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
510 snd_pcm_forward(m_pcm, -frames);
515 return (double)frames * m_formatSampleRateMul;
518 double CAESinkALSA::GetCacheTotal()
520 return (double)m_bufferSize * m_formatSampleRateMul;
523 unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
527 CLog::Log(LOGERROR, "CAESinkALSA - Tried to add packets without a sink");
531 int ret = snd_pcm_writei(m_pcm, (void*)data, frames);
534 HandleError("snd_pcm_writei(1)", ret);
535 ret = snd_pcm_writei(m_pcm, (void*)data, frames);
538 HandleError("snd_pcm_writei(2)", ret);
543 if ( ret > 0 && snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED)
544 snd_pcm_start(m_pcm);
549 void CAESinkALSA::HandleError(const char* name, int err)
554 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - underrun", name);
555 if ((err = snd_pcm_prepare(m_pcm)) < 0)
556 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err));
560 CLog::Log(LOGINFO, "CAESinkALSA::HandleError(%s) - Resuming after suspend", name);
562 /* try to resume the stream */
563 while((err = snd_pcm_resume(m_pcm)) == -EAGAIN)
566 /* if the hardware doesnt support resume, prepare the stream */
568 if ((err = snd_pcm_prepare(m_pcm)) < 0)
569 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err));
573 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_writei returned %d (%s)", name, err, snd_strerror(err));
578 void CAESinkALSA::Drain()
583 snd_pcm_drain(m_pcm);
584 snd_pcm_prepare(m_pcm);
587 void CAESinkALSA::AppendParams(std::string &device, const std::string ¶ms)
589 /* Note: escaping, e.g. "plug:'something:X=y'" isn't handled,
590 * but it is not normally encountered at this point. */
592 device += (device.find(':') == std::string::npos) ? ':' : ',';
596 bool CAESinkALSA::TryDevice(const std::string &name, snd_pcm_t **pcmp, snd_config_t *lconf)
598 /* Check if this device was already open (e.g. when checking for supported
599 * channel count in EnumerateDevice()) */
602 if (name == snd_pcm_name(*pcmp))
605 snd_pcm_close(*pcmp);
609 int err = snd_pcm_open_lconf(pcmp, name.c_str(), SND_PCM_STREAM_PLAYBACK, ALSA_OPTIONS, lconf);
612 CLog::Log(LOGINFO, "CAESinkALSA - Unable to open device \"%s\" for playback", name.c_str());
618 bool CAESinkALSA::TryDeviceWithParams(const std::string &name, const std::string ¶ms, snd_pcm_t **pcmp, snd_config_t *lconf)
622 std::string nameWithParams = name;
623 AppendParams(nameWithParams, params);
624 if (TryDevice(nameWithParams, pcmp, lconf))
628 /* Try the variant without extra parameters.
629 * Custom devices often do not take the AESx parameters, for example.
631 return TryDevice(name, pcmp, lconf);
634 bool CAESinkALSA::OpenPCMDevice(const std::string &name, const std::string ¶ms, int channels, snd_pcm_t **pcmp, snd_config_t *lconf)
636 /* Special name denoting surroundXX mangling. This is needed for some
637 * devices for multichannel to work. */
638 if (name == "@" || name.substr(0, 2) == "@:")
640 std::string openName = name.substr(1);
642 /* These device names allow alsa-lib to perform special routing if needed
643 * for multichannel to work with the audio hardware.
644 * Fall through in switch() so that devices with more channels are
645 * added as fallback. */
650 if (TryDeviceWithParams("surround40" + openName, params, pcmp, lconf))
654 if (TryDeviceWithParams("surround51" + openName, params, pcmp, lconf))
658 if (TryDeviceWithParams("surround71" + openName, params, pcmp, lconf))
662 /* Try "sysdefault" and "default" (they provide dmix if needed, and route
663 * audio to all extra channels on subdeviced cards),
664 * unless the selected devices is not DEV=0 of the card, in which case
665 * "sysdefault" and "default" would point to another device.
666 * "sysdefault" is a newish device name that won't be overwritten in case
667 * system configuration redefines "default". "default" is still tried
668 * because "sysdefault" is rather new. */
669 size_t devPos = openName.find(",DEV=");
670 if (devPos == std::string::npos || (devPos + 5 < openName.size() && openName[devPos+5] == '0'))
672 /* "sysdefault" and "default" do not have "DEV=0", drop it */
673 std::string nameWithoutDev = openName;
674 if (devPos != std::string::npos)
675 nameWithoutDev.erase(nameWithoutDev.begin() + devPos, nameWithoutDev.begin() + devPos + 6);
677 if (TryDeviceWithParams("sysdefault" + nameWithoutDev, params, pcmp, lconf)
678 || TryDeviceWithParams("default" + nameWithoutDev, params, pcmp, lconf))
682 /* Try "front" (no dmix, no audio in other channels on subdeviced cards) */
683 if (TryDeviceWithParams("front" + openName, params, pcmp, lconf))
689 /* Non-surroundXX device, just add it */
690 if (TryDeviceWithParams(name, params, pcmp, lconf))
697 void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force)
699 /* ensure that ALSA has been initialized */
700 snd_lib_error_set_handler(sndLibErrorHandler);
701 if(!snd_config || force)
704 snd_config_update_free_global();
709 snd_config_t *config;
710 snd_config_copy(&config, snd_config);
712 /* Always enumerate the default device.
713 * Note: If "default" is a stereo device, EnumerateDevice()
714 * will automatically add "@" instead to enable surroundXX mangling.
715 * We don't want to do that if "default" can handle multichannel
716 * itself (e.g. in case of a pulseaudio server). */
717 EnumerateDevice(list, "default", "", config);
721 if (snd_device_name_hint(-1, "pcm", &hints) < 0)
723 CLog::Log(LOGINFO, "CAESinkALSA - Unable to get a list of devices");
727 std::string defaultDescription;
729 for (void** hint = hints; *hint != NULL; ++hint)
731 char *io = snd_device_name_get_hint(*hint, "IOID");
732 char *name = snd_device_name_get_hint(*hint, "NAME");
733 char *desc = snd_device_name_get_hint(*hint, "DESC");
734 if ((!io || strcmp(io, "Output") == 0) && name
735 && strcmp(name, "null") != 0)
737 std::string baseName = std::string(name);
738 baseName = baseName.substr(0, baseName.find(':'));
740 if (strcmp(name, "default") == 0)
742 /* added already, but lets get the description if we have one */
744 defaultDescription = desc;
746 else if (baseName == "front")
748 /* Enumerate using the surroundXX mangling */
749 /* do not enumerate basic "front", it is already handled
750 * by the default "@" entry added in the very beginning */
751 if (strcmp(name, "front") != 0)
752 EnumerateDevice(list, std::string("@") + (name+5), desc ? desc : name, config);
755 /* Do not enumerate "default", it is already enumerated above. */
757 /* Do not enumerate the sysdefault or surroundXX devices, those are
758 * always accompanied with a "front" device and it is handled above
759 * as "@". The below devices will be automatically used if available
760 * for a "@" device. */
762 /* Ubuntu has patched their alsa-lib so that "defaults.namehint.extended"
763 * defaults to "on" instead of upstream "off", causing lots of unwanted
764 * extra devices (many of which are not actually routed properly) to be
765 * found by the enumeration process. Skip them as well ("hw", "dmix",
766 * "plughw", "dsnoop"). */
768 else if (baseName != "default"
769 && baseName != "sysdefault"
770 && baseName != "surround40"
771 && baseName != "surround41"
772 && baseName != "surround50"
773 && baseName != "surround51"
774 && baseName != "surround71"
776 && baseName != "dmix"
777 && baseName != "plughw"
778 && baseName != "dsnoop")
780 EnumerateDevice(list, name, desc ? desc : name, config);
787 snd_device_name_free_hint(hints);
789 /* set the displayname for default device */
790 if (!list.empty() && list[0].m_deviceName == "default")
792 /* If we have one from a hint (DESC), use it */
793 if (!defaultDescription.empty())
794 list[0].m_displayName = defaultDescription;
795 /* Otherwise use the discovered name or (unlikely) "Default" */
796 else if (list[0].m_displayName.empty())
797 list[0].m_displayName = "Default";
800 /* lets check uniqueness, we may need to append DEV or CARD to DisplayName */
801 /* If even a single device of card/dev X clashes with Y, add suffixes to
802 * all devices of both them, for clarity. */
804 /* clashing card names, e.g. "NVidia", "NVidia_2" */
805 std::set<std::string> cardsToAppend;
807 /* clashing basename + cardname combinations, e.g. ("hdmi","Nvidia") */
808 std::set<std::pair<std::string, std::string> > devsToAppend;
810 for (AEDeviceInfoList::iterator it1 = list.begin(); it1 != list.end(); ++it1)
812 for (AEDeviceInfoList::iterator it2 = it1+1; it2 != list.end(); ++it2)
814 if (it1->m_displayName == it2->m_displayName
815 && it1->m_displayNameExtra == it2->m_displayNameExtra)
817 /* something needs to be done */
818 std::string cardString1 = GetParamFromName(it1->m_deviceName, "CARD");
819 std::string cardString2 = GetParamFromName(it2->m_deviceName, "CARD");
821 if (cardString1 != cardString2)
823 /* card name differs, add identifiers to all devices */
824 cardsToAppend.insert(cardString1);
825 cardsToAppend.insert(cardString2);
829 std::string devString1 = GetParamFromName(it1->m_deviceName, "DEV");
830 std::string devString2 = GetParamFromName(it2->m_deviceName, "DEV");
832 if (devString1 != devString2)
834 /* device number differs, add identifiers to all such devices */
835 devsToAppend.insert(std::make_pair(it1->m_deviceName.substr(0, it1->m_deviceName.find(':')), cardString1));
836 devsToAppend.insert(std::make_pair(it2->m_deviceName.substr(0, it2->m_deviceName.find(':')), cardString2));
840 /* if we got here, the configuration is really weird, just append the whole device string */
841 it1->m_displayName += " (" + it1->m_deviceName + ")";
842 it2->m_displayName += " (" + it2->m_deviceName + ")";
847 for (std::set<std::string>::iterator it = cardsToAppend.begin();
848 it != cardsToAppend.end(); ++it)
850 for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl)
852 std::string cardString = GetParamFromName(itl->m_deviceName, "CARD");
853 if (cardString == *it)
854 /* "HDA NVidia (NVidia)", "HDA NVidia (NVidia_2)", ... */
855 itl->m_displayName += " (" + cardString + ")";
859 for (std::set<std::pair<std::string, std::string> >::iterator it = devsToAppend.begin();
860 it != devsToAppend.end(); ++it)
862 for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl)
864 std::string baseName = itl->m_deviceName.substr(0, itl->m_deviceName.find(':'));
865 std::string cardString = GetParamFromName(itl->m_deviceName, "CARD");
866 if (baseName == it->first && cardString == it->second)
868 std::string devString = GetParamFromName(itl->m_deviceName, "DEV");
869 /* "HDMI #0", "HDMI #1" ... */
870 itl->m_displayNameExtra += " #" + devString;
876 AEDeviceType CAESinkALSA::AEDeviceTypeFromName(const std::string &name)
878 if (name.substr(0, 4) == "hdmi")
879 return AE_DEVTYPE_HDMI;
880 else if (name.substr(0, 6) == "iec958" || name.substr(0, 5) == "spdif")
881 return AE_DEVTYPE_IEC958;
883 return AE_DEVTYPE_PCM;
886 std::string CAESinkALSA::GetParamFromName(const std::string &name, const std::string ¶m)
888 /* name = "hdmi:CARD=x,DEV=y" param = "CARD" => return "x" */
889 size_t parPos = name.find(param + '=');
890 if (parPos != std::string::npos)
892 parPos += param.size() + 1;
893 return name.substr(parPos, name.find_first_of(",'\"", parPos)-parPos);
899 void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config)
901 snd_pcm_t *pcmhandle = NULL;
902 if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config))
905 snd_pcm_info_t *pcminfo;
906 snd_pcm_info_alloca(&pcminfo);
907 memset(pcminfo, 0, snd_pcm_info_sizeof());
909 int err = snd_pcm_info(pcmhandle, pcminfo);
912 CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str());
913 snd_pcm_close(pcmhandle);
916 int cardNr = snd_pcm_info_get_card(pcminfo);
919 info.m_deviceName = device;
920 info.m_deviceType = AEDeviceTypeFromName(device);
924 /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */
926 if (snd_card_get_name(cardNr, &cardName) == 0)
927 info.m_displayName = cardName;
929 if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
930 info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
932 /* We already know this is HDMI, strip it */
933 info.m_displayName.erase(info.m_displayName.size()-5);
936 /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */
937 std::string pcminfoName = snd_pcm_info_get_name(pcminfo);
940 * Filter "USB Audio", in those cases snd_card_get_name() is more
943 if (pcminfoName != "USB Audio")
944 info.m_displayNameExtra = pcminfoName;
946 if (info.m_deviceType == AE_DEVTYPE_HDMI)
948 /* replace, this was likely "HDMI 0" */
949 info.m_displayNameExtra = "HDMI";
951 int dev = snd_pcm_info_get_device(pcminfo);
955 /* lets see if we can get ELD info */
957 snd_ctl_t *ctlhandle;
958 std::stringstream sstr;
959 sstr << "hw:" << cardNr;
960 std::string strHwName = sstr.str();
962 if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0)
965 if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0)
968 bool badHDMI = false;
969 if (!GetELD(hctl, dev, info, badHDMI))
970 CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)",
973 /* snd_hctl_close also closes ctlhandle */
974 snd_hctl_close(hctl);
976 // regarding data formats we don't trust ELD
977 // push all passthrough formats to the list
978 AEDataFormatList::iterator it;
979 for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
983 it = find(info.m_dataFormats.begin(), info.m_dataFormats.end(), i);
984 if (it == info.m_dataFormats.end())
985 info.m_dataFormats.push_back(i);
991 * Warn about disconnected devices, but keep them enabled
992 * Detection can go wrong on Intel, Nvidia and on all
993 * AMD (fglrx) hardware, so it is not safe to close those
996 CLog::Log(LOGDEBUG, "CAESinkALSA - HDMI device \"%s\" may be unconnected (no ELD data)", device.c_str());
1001 snd_ctl_close(ctlhandle);
1006 else if (info.m_deviceType == AE_DEVTYPE_IEC958)
1008 /* append instead of replace, pcminfoName is useful for S/PDIF */
1009 if (!info.m_displayNameExtra.empty())
1010 info.m_displayNameExtra += ' ';
1011 info.m_displayNameExtra += "S/PDIF";
1013 info.m_dataFormats.push_back(AE_FMT_AC3);
1014 info.m_dataFormats.push_back(AE_FMT_DTS);
1016 else if (info.m_displayNameExtra.empty())
1018 /* for USB audio, it gets a bit confusing as there is
1019 * - "SB Live! 24-bit External"
1020 * - "SB Live! 24-bit External, S/PDIF"
1021 * so add "Analog" qualifier to the first one */
1022 info.m_displayNameExtra = "Analog";
1025 /* "default" is a device that will be used for all inputs, while
1026 * "@" will be mangled to front/default/surroundXX as necessary */
1027 if (device == "@" || device == "default")
1029 /* Make it "Default (whatever)" */
1030 info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")");
1031 info.m_displayNameExtra = "";
1037 /* virtual devices: "default", "pulse", ... */
1038 /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is
1039 * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device",
1040 * so we only use it for virtual devices that have no better display name */
1041 info.m_displayName = description;
1044 snd_pcm_hw_params_t *hwparams;
1045 snd_pcm_hw_params_alloca(&hwparams);
1046 memset(hwparams, 0, snd_pcm_hw_params_sizeof());
1048 /* ensure we can get a playback configuration for the device */
1049 if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0)
1051 CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str());
1052 snd_pcm_close(pcmhandle);
1056 /* detect the available sample rates */
1057 for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate)
1058 if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0)
1059 info.m_sampleRates.push_back(*rate);
1061 /* detect the channels available */
1063 for (int i = ALSA_MAX_CHANNELS; i >= 1; --i)
1065 /* Reopen the device if needed on the special "surroundXX" cases */
1066 if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4))
1067 OpenPCMDevice(device, "", i, &pcmhandle, config);
1069 if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0)
1076 if (device == "default" && channels == 2)
1078 /* This looks like the ALSA standard default stereo dmix device, we
1079 * probably want to use "@" instead to get surroundXX. */
1080 snd_pcm_close(pcmhandle);
1081 EnumerateDevice(list, "@", description, config);
1085 CAEChannelInfo alsaChannels;
1086 for (int i = 0; i < channels; ++i)
1088 if (!info.m_channels.HasChannel(ALSAChannelMap[i]))
1089 info.m_channels += ALSAChannelMap[i];
1090 alsaChannels += ALSAChannelMap[i];
1093 /* remove the channels from m_channels that we cant use */
1094 info.m_channels.ResolveChannels(alsaChannels);
1096 /* detect the PCM sample formats that are available */
1097 for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
1099 if (AE_IS_RAW(i) || i == AE_FMT_MAX)
1101 snd_pcm_format_t fmt = AEFormatToALSAFormat(i);
1102 if (fmt == SND_PCM_FORMAT_UNKNOWN)
1105 if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0)
1106 info.m_dataFormats.push_back(i);
1109 snd_pcm_close(pcmhandle);
1110 list.push_back(info);
1113 bool CAESinkALSA::GetELD(snd_hctl_t *hctl, int device, CAEDeviceInfo& info, bool& badHDMI)
1117 snd_ctl_elem_id_t *id;
1118 snd_ctl_elem_info_t *einfo;
1119 snd_ctl_elem_value_t *control;
1120 snd_hctl_elem_t *elem;
1122 snd_ctl_elem_id_alloca(&id);
1123 memset(id, 0, snd_ctl_elem_id_sizeof());
1125 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
1126 snd_ctl_elem_id_set_name (id, "ELD" );
1127 snd_ctl_elem_id_set_device (id, device);
1128 elem = snd_hctl_find_elem(hctl, id);
1132 snd_ctl_elem_info_alloca(&einfo);
1133 memset(einfo, 0, snd_ctl_elem_info_sizeof());
1135 if (snd_hctl_elem_info(elem, einfo) < 0)
1138 if (!snd_ctl_elem_info_is_readable(einfo))
1141 if (snd_ctl_elem_info_get_type(einfo) != SND_CTL_ELEM_TYPE_BYTES)
1144 snd_ctl_elem_value_alloca(&control);
1145 memset(control, 0, snd_ctl_elem_value_sizeof());
1147 if (snd_hctl_elem_read(elem, control) < 0)
1150 int dataLength = snd_ctl_elem_info_get_count(einfo);
1151 /* if there is no ELD data, then its a bad HDMI device, either nothing attached OR an invalid nVidia HDMI device
1152 * OR the driver doesn't properly support ELD (notably ATI/AMD, 2012-05) */
1156 CAEELDParser::Parse(
1157 (const uint8_t*)snd_ctl_elem_value_get_bytes(control),
1162 info.m_deviceType = AE_DEVTYPE_HDMI;
1166 void CAESinkALSA::sndLibErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
1171 if (vasprintf(&errorStr, fmt, arg) >= 0)
1173 CLog::Log(LOGINFO, "CAESinkALSA - ALSA: %s:%d:(%s) %s%s%s",
1174 file, line, function, errorStr, err ? ": " : "", err ? snd_strerror(err) : "");