2 * Copyright (C) 2010-2012 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, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
29 #include "AESinkALSA.h"
30 #include "Utils/AEUtil.h"
31 #include "Utils/AEELDParser.h"
32 #include "utils/StdString.h"
33 #include "utils/log.h"
34 #include "utils/MathUtils.h"
35 #include "threads/SingleLock.h"
36 #include "settings/GUISettings.h"
38 #define ALSA_OPTIONS (SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_FORMAT | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_RESAMPLE)
39 #define ALSA_PERIODS 16
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 unsigned int ALSASampleRateList[] =
67 CAESinkALSA::CAESinkALSA() :
70 /* ensure that ALSA has been initialized */
75 CAESinkALSA::~CAESinkALSA()
80 inline CAEChannelInfo CAESinkALSA::GetChannelLayout(AEAudioFormat format)
82 unsigned int count = 0;
84 if (format.m_dataFormat == AE_FMT_AC3 ||
85 format.m_dataFormat == AE_FMT_DTS ||
86 format.m_dataFormat == AE_FMT_EAC3)
88 else if (format.m_dataFormat == AE_FMT_TRUEHD ||
89 format.m_dataFormat == AE_FMT_DTSHD)
93 for (unsigned int c = 0; c < 8; ++c)
94 for (unsigned int i = 0; i < format.m_channelLayout.Count(); ++i)
95 if (format.m_channelLayout[i] == ALSAChannelMap[c])
103 for (unsigned int i = 0; i < count; ++i)
104 info += ALSAChannelMap[i];
109 void CAESinkALSA::GetAESParams(AEAudioFormat format, std::string& params)
112 params = "AES0=0x06";
114 params = "AES0=0x04";
116 params += ",AES1=0x82,AES2=0x00";
118 if (format.m_sampleRate == 192000) params += ",AES3=0x0e";
119 else if (format.m_sampleRate == 176400) params += ",AES3=0x0c";
120 else if (format.m_sampleRate == 96000) params += ",AES3=0x0a";
121 else if (format.m_sampleRate == 88200) params += ",AES3=0x08";
122 else if (format.m_sampleRate == 48000) params += ",AES3=0x02";
123 else if (format.m_sampleRate == 44100) params += ",AES3=0x00";
124 else if (format.m_sampleRate == 32000) params += ",AES3=0x03";
125 else params += ",AES3=0x01";
128 bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device)
130 m_initDevice = device;
131 m_initFormat = format;
133 /* if we are raw, correct the data format */
134 if (AE_IS_RAW(format.m_dataFormat))
136 m_channelLayout = GetChannelLayout(format);
137 format.m_dataFormat = AE_FMT_S16NE;
138 m_passthrough = true;
142 m_channelLayout = GetChannelLayout(format);
143 m_passthrough = false;
146 if (m_channelLayout.Count() == 0)
148 CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout");
152 format.m_channelLayout = m_channelLayout;
154 std::string AESParams;
155 /* digital interfaces should have AESx set, though in practice most
156 * receivers don't care */
157 if (m_passthrough || device.substr(0, 6) == "iec958" || device.substr(0, 4) == "hdmi")
158 GetAESParams(format, AESParams);
160 CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Attempting to open device \"%s\"", device.c_str());
162 /* get the sound config */
163 snd_config_t *config;
164 snd_config_copy(&config, snd_config);
166 snd_config_t *dmixRateConf;
169 if (snd_config_search(config, "defaults.pcm.dmix.rate", &dmixRateConf) < 0
170 || snd_config_get_integer(dmixRateConf, &dmixRate) < 0)
171 dmixRate = 48000; /* assume default */
174 /* Prefer dmix for non-passthrough stereo when sample rate matches */
175 if (!OpenPCMDevice(device, AESParams, m_channelLayout.Count(), &m_pcm, config, format.m_sampleRate == dmixRate && !m_passthrough))
177 CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str());
178 snd_config_delete(config);
182 /* get the actual device name that was used */
183 device = snd_pcm_name(m_pcm);
186 CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Opened device \"%s\"", device.c_str());
188 /* free the sound config */
189 snd_config_delete(config);
191 if (!InitializeHW(format) || !InitializeSW(format))
194 snd_pcm_nonblock(m_pcm, 1);
195 snd_pcm_prepare (m_pcm);
198 m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate;
203 bool CAESinkALSA::IsCompatible(const AEAudioFormat format, const std::string device)
206 /* compare against the requested format and the real format */
207 (m_initFormat.m_sampleRate == format.m_sampleRate || m_format.m_sampleRate == format.m_sampleRate ) &&
208 (m_initFormat.m_dataFormat == format.m_dataFormat || m_format.m_dataFormat == format.m_dataFormat ) &&
209 (m_initFormat.m_channelLayout == format.m_channelLayout || m_format.m_channelLayout == format.m_channelLayout) &&
210 (m_initDevice == device)
214 snd_pcm_format_t CAESinkALSA::AEFormatToALSAFormat(const enum AEDataFormat format)
216 if (AE_IS_RAW(format))
217 return SND_PCM_FORMAT_S16;
221 case AE_FMT_S8 : return SND_PCM_FORMAT_S8;
222 case AE_FMT_U8 : return SND_PCM_FORMAT_U8;
223 case AE_FMT_S16NE : return SND_PCM_FORMAT_S16;
224 case AE_FMT_S16LE : return SND_PCM_FORMAT_S16_LE;
225 case AE_FMT_S16BE : return SND_PCM_FORMAT_S16_BE;
226 case AE_FMT_S24NE4: return SND_PCM_FORMAT_S24;
227 #ifdef __BIG_ENDIAN__
228 case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3BE;
230 case AE_FMT_S24NE3: return SND_PCM_FORMAT_S24_3LE;
232 case AE_FMT_S32NE : return SND_PCM_FORMAT_S32;
233 case AE_FMT_FLOAT : return SND_PCM_FORMAT_FLOAT;
236 return SND_PCM_FORMAT_UNKNOWN;
240 bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
242 snd_pcm_hw_params_t *hw_params;
244 snd_pcm_hw_params_alloca(&hw_params);
245 memset(hw_params, 0, snd_pcm_hw_params_sizeof());
247 snd_pcm_hw_params_any(m_pcm, hw_params);
248 snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
250 unsigned int sampleRate = format.m_sampleRate;
251 unsigned int channelCount = format.m_channelLayout.Count();
252 snd_pcm_hw_params_set_rate_near (m_pcm, hw_params, &sampleRate, NULL);
253 snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount);
255 /* ensure we opened X channels or more */
256 if (format.m_channelLayout.Count() > channelCount)
258 CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to open the required number of channels");
262 /* update the channelLayout to what we managed to open */
263 format.m_channelLayout.Reset();
264 for (unsigned int i = 0; i < channelCount; ++i)
265 format.m_channelLayout += ALSAChannelMap[i];
267 snd_pcm_format_t fmt = AEFormatToALSAFormat(format.m_dataFormat);
268 if (fmt == SND_PCM_FORMAT_UNKNOWN)
270 /* if we dont support the requested format, fallback to float */
271 format.m_dataFormat = AE_FMT_FLOAT;
272 fmt = SND_PCM_FORMAT_FLOAT;
275 /* try the data format */
276 if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
278 /* if the chosen format is not supported, try each one in decending order */
279 CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat));
280 for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
282 if (AE_IS_RAW(i) || i == AE_FMT_MAX)
285 if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE)
288 fmt = AEFormatToALSAFormat(i);
290 if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
292 fmt = SND_PCM_FORMAT_UNKNOWN;
296 int fmtBits = CAEUtil::DataFormatToBits(i);
297 int bits = snd_pcm_hw_params_get_sbits(hw_params);
300 /* if we opened in 32bit and only have 24bits, pack into 24 */
301 if (fmtBits == 32 && bits == 24)
307 /* record that the format fell back to X */
308 format.m_dataFormat = i;
309 CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
313 /* if we failed to find a valid output format */
314 if (fmt == SND_PCM_FORMAT_UNKNOWN)
316 CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format");
321 unsigned int periods;
323 snd_pcm_uframes_t periodSize, bufferSize;
324 snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize);
326 bufferSize = std::min(bufferSize, (snd_pcm_uframes_t)8192);
327 periodSize = bufferSize / ALSA_PERIODS;
328 periods = ALSA_PERIODS;
330 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);
332 /* work on a copy of the hw params */
333 snd_pcm_hw_params_t *hw_params_copy;
334 snd_pcm_hw_params_alloca(&hw_params_copy);
336 /* try to set the buffer size then the period size */
337 snd_pcm_hw_params_copy(hw_params_copy, hw_params);
338 snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
339 snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
340 snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
341 if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
343 /* try to set the period size then the buffer size */
344 snd_pcm_hw_params_copy(hw_params_copy, hw_params);
345 snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
346 snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
347 snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
348 if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
350 /* try to just set the buffer size */
351 snd_pcm_hw_params_copy(hw_params_copy, hw_params);
352 snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
353 snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
354 if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
356 /* try to just set the period size */
357 snd_pcm_hw_params_copy(hw_params_copy, hw_params);
358 snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
359 snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
360 if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
362 CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Failed to set the parameters");
369 snd_pcm_hw_params_get_period_size(hw_params_copy, &periodSize, NULL);
370 snd_pcm_hw_params_get_buffer_size(hw_params_copy, &bufferSize);
373 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);
375 /* set the format parameters */
376 format.m_sampleRate = sampleRate;
377 format.m_frames = periodSize;
378 format.m_frameSamples = periodSize * format.m_channelLayout.Count();
379 format.m_frameSize = snd_pcm_frames_to_bytes(m_pcm, 1);
381 m_bufferSize = (unsigned int)bufferSize;
382 m_timeout = std::ceil((double)(bufferSize * 1000) / (double)sampleRate);
384 CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout);
389 bool CAESinkALSA::InitializeSW(AEAudioFormat &format)
391 snd_pcm_sw_params_t *sw_params;
392 snd_pcm_uframes_t boundary;
394 snd_pcm_sw_params_alloca(&sw_params);
395 memset(sw_params, 0, snd_pcm_sw_params_sizeof());
397 snd_pcm_sw_params_current (m_pcm, sw_params);
398 snd_pcm_sw_params_set_start_threshold (m_pcm, sw_params, INT_MAX);
399 snd_pcm_sw_params_set_silence_threshold(m_pcm, sw_params, 0);
400 snd_pcm_sw_params_get_boundary (sw_params, &boundary);
401 snd_pcm_sw_params_set_silence_size (m_pcm, sw_params, boundary);
402 snd_pcm_sw_params_set_avail_min (m_pcm, sw_params, format.m_frames);
404 if (snd_pcm_sw_params(m_pcm, sw_params) < 0)
406 CLog::Log(LOGERROR, "CAESinkALSA::InitializeSW - Failed to set the parameters");
413 void CAESinkALSA::Deinitialize()
419 snd_pcm_drop (m_pcm);
420 snd_pcm_close(m_pcm);
425 void CAESinkALSA::Stop()
432 double CAESinkALSA::GetDelay()
436 snd_pcm_sframes_t frames = 0;
437 snd_pcm_delay(m_pcm, &frames);
441 #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
442 snd_pcm_forward(m_pcm, -frames);
447 return (double)frames * m_formatSampleRateMul;
450 double CAESinkALSA::GetCacheTime()
455 int space = snd_pcm_avail_update(m_pcm);
458 snd_pcm_state_t state = snd_pcm_state(m_pcm);
461 HandleError("snd_pcm_state", state);
462 space = m_bufferSize;
465 if (state != SND_PCM_STATE_RUNNING && state != SND_PCM_STATE_PREPARED)
466 space = m_bufferSize;
469 return (double)(m_bufferSize - space) * m_formatSampleRateMul;
472 double CAESinkALSA::GetCacheTotal()
474 return (double)m_bufferSize * m_formatSampleRateMul;
477 unsigned int CAESinkALSA::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio)
482 if (snd_pcm_state(m_pcm) == SND_PCM_STATE_PREPARED)
483 snd_pcm_start(m_pcm);
487 ret = snd_pcm_avail(m_pcm);
490 HandleError("snd_pcm_avail", ret);
494 if ((unsigned int)ret < frames);
496 ret = snd_pcm_wait(m_pcm, m_timeout);
498 HandleError("snd_pcm_wait", ret);
501 ret = snd_pcm_writei(m_pcm, (void*)data, frames);
504 HandleError("snd_pcm_writei(1)", ret);
505 ret = snd_pcm_writei(m_pcm, (void*)data, frames);
508 HandleError("snd_pcm_writei(2)", ret);
516 void CAESinkALSA::HandleError(const char* name, int err)
521 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - underrun", name);
522 if ((err = snd_pcm_prepare(m_pcm)) < 0)
523 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err));
527 CLog::Log(LOGINFO, "CAESinkALSA::HandleError(%s) - Resuming after suspend", name);
529 /* try to resume the stream */
530 while((err = snd_pcm_resume(m_pcm)) == -EAGAIN)
533 /* if the hardware doesnt support resume, prepare the stream */
535 if ((err = snd_pcm_prepare(m_pcm)) < 0)
536 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_prepare returned %d (%s)", name, err, snd_strerror(err));
540 CLog::Log(LOGERROR, "CAESinkALSA::HandleError(%s) - snd_pcm_writei returned %d (%s)", name, err, snd_strerror(err));
545 void CAESinkALSA::Drain()
550 snd_pcm_nonblock(m_pcm, 0);
551 snd_pcm_drain(m_pcm);
552 snd_pcm_nonblock(m_pcm, 1);
555 void CAESinkALSA::AppendParams(std::string &device, const std::string ¶ms)
557 /* Note: escaping, e.g. "plug:'something:X=y'" isn't handled,
558 * but it is not normally encountered at this point. */
560 device += (device.find(':') == std::string::npos) ? ':' : ',';
564 bool CAESinkALSA::TryDevice(const std::string &name, snd_pcm_t **pcmp, snd_config_t *lconf)
566 /* Check if this device was already open (e.g. when checking for supported
567 * channel count in EnumerateDevice()) */
570 if (name == snd_pcm_name(*pcmp))
573 snd_pcm_close(*pcmp);
577 int err = snd_pcm_open_lconf(pcmp, name.c_str(), SND_PCM_STREAM_PLAYBACK, ALSA_OPTIONS, lconf);
580 CLog::Log(LOGINFO, "CAESinkALSA - Unable to open device \"%s\" for playback", name.c_str());
586 bool CAESinkALSA::TryDeviceWithParams(const std::string &name, const std::string ¶ms, snd_pcm_t **pcmp, snd_config_t *lconf)
590 std::string nameWithParams = name;
591 AppendParams(nameWithParams, params);
592 if (TryDevice(nameWithParams, pcmp, lconf))
596 /* Try the variant without extra parameters.
597 * Custom devices often do not take the AESx parameters, for example.
599 return TryDevice(name, pcmp, lconf);
602 bool CAESinkALSA::OpenPCMDevice(const std::string &name, const std::string ¶ms, int channels, snd_pcm_t **pcmp, snd_config_t *lconf, bool preferDmixStereo)
604 /* Special name denoting surroundXX mangling. This is needed for some
605 * devices for multichannel to work. */
606 if (name == "@" || name.substr(0, 2) == "@:")
608 std::string openName = name.substr(1);
610 /* These device names allow alsa-lib to perform special routing if needed
611 * for multichannel to work with the audio hardware.
612 * Fall through in switch() so that devices with more channels are
613 * added as fallback. */
618 if (TryDeviceWithParams("surround40" + openName, params, pcmp, lconf))
622 if (TryDeviceWithParams("surround51" + openName, params, pcmp, lconf))
626 if (TryDeviceWithParams("surround71" + openName, params, pcmp, lconf))
630 /* If preferDmix is false, try non-dmix configuration first.
631 * This allows output with non-48000 sample rate if device is free */
632 if (!preferDmixStereo && TryDeviceWithParams("front" + openName, params, pcmp, lconf))
635 /* Try "sysdefault" and "default" (they provide dmix),
636 * unless the selected devices is not DEV=0 of the card, in which case
637 * "sysdefault" and "default" would point to another device.
638 * "sysdefault" is a newish device name that won't be overwritten in case
639 * system configuration redefines "default". "default" is still tried
640 * because "sysdefault" is rather new. */
641 size_t devPos = openName.find(",DEV=");
642 if (devPos == std::string::npos || (devPos + 5 < openName.size() && openName[devPos+5] == '0'))
644 /* "sysdefault" and "default" do not have "DEV=0", drop it */
645 std::string nameWithoutDev = openName;
646 if (devPos != std::string::npos)
647 nameWithoutDev.erase(nameWithoutDev.begin() + devPos, nameWithoutDev.begin() + devPos + 6);
649 if (TryDeviceWithParams("sysdefault" + nameWithoutDev, params, pcmp, lconf)
650 || TryDeviceWithParams("default" + nameWithoutDev, params, pcmp, lconf))
654 /* Try non-dmix "front" */
655 if (preferDmixStereo && TryDeviceWithParams("front" + openName, params, pcmp, lconf))
661 /* Non-surroundXX device, just add it */
662 if (TryDeviceWithParams(name, params, pcmp, lconf))
669 void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list)
671 /* ensure that ALSA has been initialized */
672 snd_lib_error_set_handler(sndLibErrorHandler);
676 snd_config_t *config;
677 snd_config_copy(&config, snd_config);
679 /* Always enumerate the default device.
680 * Note: If "default" is a stereo device, EnumerateDevice()
681 * will automatically add "@" instead to enable surroundXX mangling.
682 * We don't want to do that if "default" can handle multichannel
683 * itself (e.g. in case of a pulseaudio server). */
684 EnumerateDevice(list, "default", "", config);
688 if (snd_device_name_hint(-1, "pcm", &hints) < 0)
690 CLog::Log(LOGINFO, "CAESinkALSA - Unable to get a list of devices");
694 std::string defaultDescription;
696 for (void** hint = hints; *hint != NULL; ++hint)
698 char *io = snd_device_name_get_hint(*hint, "IOID");
699 char *name = snd_device_name_get_hint(*hint, "NAME");
700 char *desc = snd_device_name_get_hint(*hint, "DESC");
701 if ((!io || strcmp(io, "Output") == 0) && name
702 && strcmp(name, "null") != 0)
704 std::string baseName = std::string(name);
705 baseName = baseName.substr(0, baseName.find(':'));
707 if (strcmp(name, "default") == 0)
709 /* added already, but lets get the description if we have one */
711 defaultDescription = desc;
713 else if (baseName == "front")
715 /* Enumerate using the surroundXX mangling */
716 /* do not enumerate basic "front", it is already handled
717 * by the default "@" entry added in the very beginning */
718 if (strcmp(name, "front") != 0)
719 EnumerateDevice(list, std::string("@") + (name+5), desc ? desc : name, config);
721 /* Do not enumerate the sysdefault or surroundXX devices, those are
722 * always accompanied with a "front" device and it is handled above
723 * as "@". The below devices will be automatically used if available
724 * for a "@" device. */
725 else if (baseName != "default"
726 && baseName != "sysdefault"
727 && baseName != "surround40"
728 && baseName != "surround41"
729 && baseName != "surround50"
730 && baseName != "surround51"
731 && baseName != "surround71")
733 EnumerateDevice(list, name, desc ? desc : name, config);
740 snd_device_name_free_hint(hints);
742 /* set the displayname for default device */
743 if (!list.empty() && list[0].m_deviceName == "default")
745 /* If we have one from a hint (DESC), use it */
746 if (!defaultDescription.empty())
747 list[0].m_displayName = defaultDescription;
748 /* Otherwise use the discovered name or (unlikely) "Default" */
749 else if (list[0].m_displayName.empty())
750 list[0].m_displayName = "Default";
753 /* lets check uniqueness, we may need to append DEV or CARD to DisplayName */
754 /* If even a single device of card/dev X clashes with Y, add suffixes to
755 * all devices of both them, for clarity. */
757 /* clashing card names, e.g. "NVidia", "NVidia_2" */
758 std::set<std::string> cardsToAppend;
760 /* clashing basename + cardname combinations, e.g. ("hdmi","Nvidia") */
761 std::set<std::pair<std::string, std::string> > devsToAppend;
763 for (AEDeviceInfoList::iterator it1 = list.begin(); it1 != list.end(); ++it1)
765 for (AEDeviceInfoList::iterator it2 = it1+1; it2 != list.end(); ++it2)
767 if (it1->m_displayName == it2->m_displayName
768 && it1->m_displayNameExtra == it2->m_displayNameExtra)
770 /* something needs to be done */
771 std::string cardString1;
772 std::string cardString2;
773 GetParamFromName(it1->m_deviceName, "CARD", cardString1);
774 GetParamFromName(it2->m_deviceName, "CARD", cardString2);
776 if (cardString1 != cardString2)
778 /* card name differs, add identifiers to all devices */
779 cardsToAppend.insert(cardString1);
780 cardsToAppend.insert(cardString2);
784 std::string devString1;
785 std::string devString2;
786 GetParamFromName(it1->m_deviceName, "DEV", devString1);
787 GetParamFromName(it2->m_deviceName, "DEV", devString2);
789 if (devString1 != devString2)
791 /* device number differs, add identifiers to all such devices */
792 devsToAppend.insert(std::make_pair(it1->m_deviceName.substr(0, it1->m_deviceName.find(':')), cardString1));
793 devsToAppend.insert(std::make_pair(it2->m_deviceName.substr(0, it2->m_deviceName.find(':')), cardString2));
797 /* if we got here, the configuration is really weird, just give up */
798 it1->m_displayName = it1->m_deviceName;
799 it2->m_displayName = it2->m_deviceName;
804 for (std::set<std::string>::iterator it = cardsToAppend.begin();
805 it != cardsToAppend.end(); ++it)
807 for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl)
809 std::string cardString;
810 GetParamFromName(itl->m_deviceName, "CARD", cardString);
811 if (cardString == *it)
812 /* "HDA NVidia (NVidia)", "HDA NVidia (NVidia_2)", ... */
813 itl->m_displayName += " (" + cardString + ")";
817 for (std::set<std::pair<std::string, std::string> >::iterator it = devsToAppend.begin();
818 it != devsToAppend.end(); ++it)
820 for (AEDeviceInfoList::iterator itl = list.begin(); itl != list.end(); ++itl)
822 std::string baseName = itl->m_deviceName.substr(0, itl->m_deviceName.find(':'));
823 std::string cardString;
824 GetParamFromName(itl->m_deviceName, "CARD", cardString);
825 if (baseName == it->first && cardString == it->second)
827 std::string devString;
828 GetParamFromName(itl->m_deviceName, "DEV", devString);
829 /* "HDMI #0", "HDMI #1" ... */
830 itl->m_displayNameExtra += " #" + devString;
836 void CAESinkALSA::GetParamFromName(const std::string &name, const std::string ¶m, std::string &value)
838 /* name = "hdmi:CARD=x,DEV=y" param = "CARD" => value = "x" */
839 size_t parPos = name.find(param + '=');
840 if (parPos != std::string::npos)
842 parPos += param.size() + 1;
843 value = name.substr(parPos, name.find_first_of(",'\"", parPos)-parPos);
851 void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config)
853 snd_pcm_t *pcmhandle = NULL;
854 if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config, false))
857 snd_pcm_info_t *pcminfo;
858 snd_pcm_info_alloca(&pcminfo);
859 memset(pcminfo, 0, snd_pcm_info_sizeof());
861 int err = snd_pcm_info(pcmhandle, pcminfo);
864 CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str());
865 snd_pcm_close(pcmhandle);
868 int cardNr = snd_pcm_info_get_card(pcminfo);
871 info.m_deviceName = device;
873 bool isHDMI = (device.substr(0, 4) == "hdmi");
874 bool isSPDIF = (device.substr(0, 6) == "iec958");
877 info.m_deviceType = AE_DEVTYPE_HDMI;
879 info.m_deviceType = AE_DEVTYPE_IEC958;
881 info.m_deviceType = AE_DEVTYPE_PCM;
885 /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */
887 if (snd_card_get_name(cardNr, &cardName) == 0)
888 info.m_displayName = cardName;
890 if (isHDMI && info.m_displayName.size() > 5 &&
891 info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
893 /* We already know this is HDMI, strip it */
894 info.m_displayName.erase(info.m_displayName.size()-5);
897 /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */
898 std::string pcminfoName = snd_pcm_info_get_name(pcminfo);
901 * Filter "USB Audio", in those cases snd_card_get_name() is more
904 if (pcminfoName != "USB Audio")
905 info.m_displayNameExtra = pcminfoName;
909 /* replace, this was likely "HDMI 0" */
910 info.m_displayNameExtra = "HDMI";
912 int dev = snd_pcm_info_get_device(pcminfo);
916 /* lets see if we can get ELD info */
918 snd_ctl_t *ctlhandle;
919 std::stringstream sstr;
920 sstr << "hw:" << cardNr;
921 std::string strHwName = sstr.str();
923 if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0)
926 if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0)
929 bool badHDMI = false;
930 if (!GetELD(hctl, dev, info, badHDMI))
931 CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)",
934 /* snd_hctl_close also closes ctlhandle */
935 snd_hctl_close(hctl);
939 /* unconnected HDMI port */
940 CLog::Log(LOGDEBUG, "CAESinkALSA - Skipping HDMI device \"%s\" as it has no ELD data", device.c_str());
941 snd_pcm_close(pcmhandle);
947 snd_ctl_close(ctlhandle);
954 /* append instead of replace, pcminfoName is useful for S/PDIF */
955 if (!info.m_displayNameExtra.empty())
956 info.m_displayNameExtra += ' ';
957 info.m_displayNameExtra += "S/PDIF";
959 else if (info.m_displayNameExtra.empty())
961 /* for USB audio, it gets a bit confusing as there is
962 * - "SB Live! 24-bit External"
963 * - "SB Live! 24-bit External, S/PDIF"
964 * so add "Analog" qualifier to the first one */
965 info.m_displayNameExtra = "Analog";
968 /* "default" is a device that will be used for all inputs, while
969 * "@" will be mangled to front/default/surroundXX as necessary */
970 if (device == "@" || device == "default")
972 /* Make it "Default (whatever)" */
973 info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")");
974 info.m_displayNameExtra = "";
980 /* virtual devices: "default", "pulse", ... */
981 /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is
982 * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device",
983 * so we only use it for virtual devices that have no better display name */
984 info.m_displayName = description;
987 snd_pcm_hw_params_t *hwparams;
988 snd_pcm_hw_params_alloca(&hwparams);
989 memset(hwparams, 0, snd_pcm_hw_params_sizeof());
991 /* ensure we can get a playback configuration for the device */
992 if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0)
994 CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str());
995 snd_pcm_close(pcmhandle);
999 /* detect the available sample rates */
1000 for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate)
1001 if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0)
1002 info.m_sampleRates.push_back(*rate);
1004 /* detect the channels available */
1006 for (int i = ALSA_MAX_CHANNELS; i >= 1; --i)
1008 /* Reopen the device if needed on the special "surroundXX" cases */
1009 if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4))
1010 OpenPCMDevice(device, "", i, &pcmhandle, config, false);
1012 if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0)
1019 if (device == "default" && channels == 2)
1021 /* This looks like the ALSA standard default stereo dmix device, we
1022 * probably want to use "@" instead to get surroundXX. */
1023 snd_pcm_close(pcmhandle);
1024 EnumerateDevice(list, "@", description, config);
1028 CAEChannelInfo alsaChannels;
1029 for (int i = 0; i < channels; ++i)
1031 if (!info.m_channels.HasChannel(ALSAChannelMap[i]))
1032 info.m_channels += ALSAChannelMap[i];
1033 alsaChannels += ALSAChannelMap[i];
1036 /* remove the channels from m_channels that we cant use */
1037 info.m_channels.ResolveChannels(alsaChannels);
1039 /* detect the PCM sample formats that are available */
1040 for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
1042 if (AE_IS_RAW(i) || i == AE_FMT_MAX)
1044 snd_pcm_format_t fmt = AEFormatToALSAFormat(i);
1045 if (fmt == SND_PCM_FORMAT_UNKNOWN)
1048 if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0)
1049 info.m_dataFormats.push_back(i);
1052 snd_pcm_close(pcmhandle);
1053 list.push_back(info);
1056 bool CAESinkALSA::GetELD(snd_hctl_t *hctl, int device, CAEDeviceInfo& info, bool& badHDMI)
1060 snd_ctl_elem_id_t *id;
1061 snd_ctl_elem_info_t *einfo;
1062 snd_ctl_elem_value_t *control;
1063 snd_hctl_elem_t *elem;
1065 snd_ctl_elem_id_alloca(&id);
1066 memset(id, 0, snd_ctl_elem_id_sizeof());
1068 snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
1069 snd_ctl_elem_id_set_name (id, "ELD" );
1070 snd_ctl_elem_id_set_device (id, device);
1071 elem = snd_hctl_find_elem(hctl, id);
1075 snd_ctl_elem_info_alloca(&einfo);
1076 memset(einfo, 0, snd_ctl_elem_info_sizeof());
1078 if (snd_hctl_elem_info(elem, einfo) < 0)
1081 if (!snd_ctl_elem_info_is_readable(einfo))
1084 if (snd_ctl_elem_info_get_type(einfo) != SND_CTL_ELEM_TYPE_BYTES)
1087 snd_ctl_elem_value_alloca(&control);
1088 memset(control, 0, snd_ctl_elem_value_sizeof());
1090 if (snd_hctl_elem_read(elem, control) < 0)
1093 int dataLength = snd_ctl_elem_info_get_count(einfo);
1094 /* if there is no ELD data, then its a bad HDMI device, either nothing attached OR an invalid nVidia HDMI device */
1098 CAEELDParser::Parse(
1099 (const uint8_t*)snd_ctl_elem_value_get_bytes(control),
1104 info.m_deviceType = AE_DEVTYPE_HDMI;
1108 void CAESinkALSA::sndLibErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
1113 if (vasprintf(&errorStr, fmt, arg) >= 0)
1115 CLog::Log(LOGINFO, "CAESinkALSA - ALSA: %s:%d:(%s) %s%s%s",
1116 file, line, function, errorStr, err ? ": " : "", err ? snd_strerror(err) : "");