bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) { m_initDevice = device; m_initFormat = format; /* if we are raw, correct the data format */ if (AE_IS_RAW(format.m_dataFormat)) { m_channelLayout = GetChannelLayout(format); format.m_dataFormat = AE_FMT_S16NE; m_passthrough = true; } else { m_channelLayout = GetChannelLayout(format); m_passthrough = false; } if (m_channelLayout.Count() == 0) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout"); return false; } format.m_channelLayout = m_channelLayout; /* if passthrough we need the additional AES flags */ if (m_passthrough) GetPassthroughDevice(format, device); m_device = device; CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Attempting to open device %s", device.c_str()); /* get the sound config */ snd_config_t *config; snd_config_copy(&config, snd_config); int error; error = snd_pcm_open_lconf(&m_pcm, device.c_str(), SND_PCM_STREAM_PLAYBACK, ALSA_OPTIONS, config); if (error < 0) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - snd_pcm_open_lconf(%d) - %s", error, device.c_str()); snd_config_delete(config); return false; } /* free the sound config */ snd_config_delete(config); if (!InitializeHW(format) || !InitializeSW(format)) return false; snd_pcm_nonblock(m_pcm, 1); snd_pcm_prepare (m_pcm); m_format = format; m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate; return true; }
bool CAESinkOSS::IsCompatible(const AEAudioFormat &format, const std::string &device) { AEAudioFormat tmp = format; tmp.m_channelLayout = GetChannelLayout(format); return ( tmp.m_sampleRate == m_initFormat.m_sampleRate && tmp.m_dataFormat == m_initFormat.m_dataFormat && tmp.m_channelLayout == m_initFormat.m_channelLayout && GetDeviceUse(tmp, device) == m_device ); }
bool CAESinkOSS::Initialize(AEAudioFormat &format, std::string &device) { m_initFormat = format; format.m_channelLayout = GetChannelLayout(format); device = GetDeviceUse(format, device); #ifdef __linux__ /* try to open in exclusive mode first (no software mixing) */ m_fd = open(device.c_str(), O_WRONLY | O_EXCL, 0); if (m_fd == -1) #endif m_fd = open(device.c_str(), O_WRONLY, 0); if (m_fd == -1) { CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to open the audio device: %s", device.c_str()); return false; } int format_mask; if (ioctl(m_fd, SNDCTL_DSP_GETFMTS, &format_mask) == -1) { close(m_fd); CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to get supported formats, assuming AFMT_S16_NE"); return false; } #ifdef OSS4 bool useCooked = true; #endif int oss_fmt = 0; #ifdef AFMT_FLOAT if ((format.m_dataFormat == AE_FMT_FLOAT) && (format_mask & AFMT_FLOAT )) oss_fmt = AFMT_FLOAT; else #endif #ifdef AFMT_S32_NE if ((format.m_dataFormat == AE_FMT_S32NE) && (format_mask & AFMT_S32_NE)) oss_fmt = AFMT_S32_NE; else if ((format.m_dataFormat == AE_FMT_S32BE) && (format_mask & AFMT_S32_BE)) oss_fmt = AFMT_S32_BE; else if ((format.m_dataFormat == AE_FMT_S32LE) && (format_mask & AFMT_S32_LE)) oss_fmt = AFMT_S32_LE; else #endif if ((format.m_dataFormat == AE_FMT_S16NE) && (format_mask & AFMT_S16_NE)) oss_fmt = AFMT_S16_NE; else if ((format.m_dataFormat == AE_FMT_S16BE) && (format_mask & AFMT_S16_BE)) oss_fmt = AFMT_S16_BE; else if ((format.m_dataFormat == AE_FMT_S16LE) && (format_mask & AFMT_S16_LE)) oss_fmt = AFMT_S16_LE; else if ((format.m_dataFormat == AE_FMT_S8 ) && (format_mask & AFMT_S8 )) oss_fmt = AFMT_S8; else if ((format.m_dataFormat == AE_FMT_U8 ) && (format_mask & AFMT_U8 )) oss_fmt = AFMT_U8; else if ((AE_IS_RAW(format.m_dataFormat) ) && (format_mask & AFMT_AC3 )) { oss_fmt = AFMT_AC3; format.m_dataFormat = AE_FMT_S16NE; } else if (AE_IS_RAW(format.m_dataFormat)) { close(m_fd); CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to find a suitable RAW output format"); return false; } else { CLog::Log(LOGINFO, "CAESinkOSS::Initialize - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat)); /* fallback to the best supported format */ #ifdef AFMT_FLOAT if (format_mask & AFMT_FLOAT ) { oss_fmt = AFMT_FLOAT; format.m_dataFormat = AE_FMT_FLOAT; } else #endif #ifdef AFMT_S32_NE if (format_mask & AFMT_S32_NE) { oss_fmt = AFMT_S32_NE; format.m_dataFormat = AE_FMT_S32NE; } else if (format_mask & AFMT_S32_BE) { oss_fmt = AFMT_S32_BE; format.m_dataFormat = AE_FMT_S32BE; } else if (format_mask & AFMT_S32_LE) { oss_fmt = AFMT_S32_LE; format.m_dataFormat = AE_FMT_S32LE; } else #endif if (format_mask & AFMT_S16_NE) { oss_fmt = AFMT_S16_NE; format.m_dataFormat = AE_FMT_S16NE; } else if (format_mask & AFMT_S16_BE) { oss_fmt = AFMT_S16_BE; format.m_dataFormat = AE_FMT_S16BE; } else if (format_mask & AFMT_S16_LE) { oss_fmt = AFMT_S16_LE; format.m_dataFormat = AE_FMT_S16LE; } else if (format_mask & AFMT_S8 ) { oss_fmt = AFMT_S8; format.m_dataFormat = AE_FMT_S8; } else if (format_mask & AFMT_U8 ) { oss_fmt = AFMT_U8; format.m_dataFormat = AE_FMT_U8; } else { CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to find a suitable native output format, will try to use AE_FMT_S16NE anyway"); oss_fmt = AFMT_S16_NE; format.m_dataFormat = AE_FMT_S16NE; #ifdef OSS4 /* dont use cooked if we did not find a native format, OSS might be able to convert */ useCooked = false; #endif } } #ifdef OSS4 if (useCooked) { int oss_cooked = 1; if (ioctl(m_fd, SNDCTL_DSP_COOKEDMODE, &oss_cooked) == -1) CLog::Log(LOGWARNING, "CAESinkOSS::Initialize - Failed to set cooked mode"); } #endif if (ioctl(m_fd, SNDCTL_DSP_SETFMT, &oss_fmt) == -1) { close(m_fd); CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to set the data format (%s)", CAEUtil::DataFormatToStr(format.m_dataFormat)); return false; } /* find the number we need to open to access the channels we need */ bool found = false; int oss_ch = 0; for (int ch = format.m_channelLayout.Count(); ch < 9; ++ch) { oss_ch = ch; if (ioctl(m_fd, SNDCTL_DSP_CHANNELS, &oss_ch) != -1 && oss_ch >= (int)format.m_channelLayout.Count()) { found = true; break; } } if (!found) CLog::Log(LOGWARNING, "CAESinkOSS::Initialize - Failed to access the number of channels required, falling back"); #if defined(TARGET_FREEBSD) /* fix hdmi 8 channels order */ if ((oss_fmt != AFMT_AC3) && 8 == oss_ch) { unsigned long long order = 0x0000000087346521ULL; if (ioctl(m_fd, SNDCTL_DSP_SET_CHNORDER, &order) == -1) CLog::Log(LOGWARNING, "CAESinkOSS::Initialize - Failed to set the channel order"); } #elif defined(OSS4) unsigned long long order = 0; for (unsigned int i = 0; i < format.m_channelLayout.Count(); ++i) switch (format.m_channelLayout[i]) { case AE_CH_FL : order = (order << 4) | CHID_L ; break; case AE_CH_FR : order = (order << 4) | CHID_R ; break; case AE_CH_FC : order = (order << 4) | CHID_C ; break; case AE_CH_LFE: order = (order << 4) | CHID_LFE; break; case AE_CH_SL : order = (order << 4) | CHID_LS ; break; case AE_CH_SR : order = (order << 4) | CHID_RS ; break; case AE_CH_BL : order = (order << 4) | CHID_LR ; break; case AE_CH_BR : order = (order << 4) | CHID_RR ; break; default: continue; } if (ioctl(m_fd, SNDCTL_DSP_SET_CHNORDER, &order) == -1) { if (ioctl(m_fd, SNDCTL_DSP_GET_CHNORDER, &order) == -1) { CLog::Log(LOGWARNING, "CAESinkOSS::Initialize - Failed to get the channel order, assuming CHNORDER_NORMAL"); } } #endif int tmp = (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3) * format.m_channelLayout.Count() * OSS_FRAMES; int pos = 0; while ((tmp & 0x1) == 0x0) { tmp = tmp >> 1; ++pos; } int oss_frag = (4 << 16) | pos; if (ioctl(m_fd, SNDCTL_DSP_SETFRAGMENT, &oss_frag) == -1) CLog::Log(LOGWARNING, "CAESinkOSS::Initialize - Failed to set the fragment size"); int oss_sr = format.m_sampleRate; if (ioctl(m_fd, SNDCTL_DSP_SPEED, &oss_sr) == -1) { close(m_fd); CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to set the sample rate"); return false; } audio_buf_info bi; if (ioctl(m_fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) { close(m_fd); CLog::Log(LOGERROR, "CAESinkOSS::Initialize - Failed to get the output buffer size"); return false; } format.m_sampleRate = oss_sr; format.m_frameSize = (CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3) * format.m_channelLayout.Count(); format.m_frames = bi.fragsize / format.m_frameSize; format.m_frameSamples = format.m_frames * format.m_channelLayout.Count(); m_device = device; m_format = format; return true; }
bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) { CAEChannelInfo channelLayout; m_initDevice = device; m_initFormat = format; /* if we are raw, correct the data format */ if (AE_IS_RAW(format.m_dataFormat)) { channelLayout = GetChannelLayout(format); format.m_dataFormat = AE_FMT_S16NE; m_passthrough = true; } else { channelLayout = GetChannelLayout(format); m_passthrough = false; } #if defined(HAS_LIBAMCODEC) if (aml_present()) { aml_set_audio_passthrough(m_passthrough); device = "default"; } #endif if (channelLayout.Count() == 0) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout"); return false; } format.m_channelLayout = channelLayout; AEDeviceType devType = AEDeviceTypeFromName(device); std::string AESParams; /* digital interfaces should have AESx set, though in practice most * receivers don't care */ if (m_passthrough || devType == AE_DEVTYPE_HDMI || devType == AE_DEVTYPE_IEC958) GetAESParams(format, AESParams); CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Attempting to open device \"%s\"", device.c_str()); /* get the sound config */ snd_config_t *config; snd_config_copy(&config, snd_config); if (!OpenPCMDevice(device, AESParams, channelLayout.Count(), &m_pcm, config)) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str()); snd_config_delete(config); return false; } /* get the actual device name that was used */ device = snd_pcm_name(m_pcm); m_device = device; CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Opened device \"%s\"", device.c_str()); /* free the sound config */ snd_config_delete(config); if (!InitializeHW(format) || !InitializeSW(format)) return false; // we want it blocking snd_pcm_nonblock(m_pcm, 0); snd_pcm_prepare (m_pcm); m_format = format; m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate; return true; }
bool CAESinkALSA::Initialize(AEAudioFormat &format, std::string &device) { m_initDevice = device; m_initFormat = format; /* if we are raw, correct the data format */ if (AE_IS_RAW(format.m_dataFormat)) { m_channelLayout = GetChannelLayout(format); format.m_dataFormat = AE_FMT_S16NE; m_passthrough = true; } else { m_channelLayout = GetChannelLayout(format); m_passthrough = false; } if (m_channelLayout.Count() == 0) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - Unable to open the requested channel layout"); return false; } format.m_channelLayout = m_channelLayout; AEDeviceType devType = AEDeviceTypeFromName(device); std::string AESParams; /* digital interfaces should have AESx set, though in practice most * receivers don't care */ if (m_passthrough || devType == AE_DEVTYPE_HDMI || devType == AE_DEVTYPE_IEC958) GetAESParams(format, AESParams); CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Attempting to open device \"%s\"", device.c_str()); /* get the sound config */ snd_config_t *config; snd_config_copy(&config, snd_config); snd_config_t *dmixRateConf; long dmixRate; if (snd_config_search(config, "defaults.pcm.dmix.rate", &dmixRateConf) < 0 || snd_config_get_integer(dmixRateConf, &dmixRate) < 0) dmixRate = 48000; /* assume default */ /* Prefer dmix for non-passthrough stereo when sample rate matches */ if (!OpenPCMDevice(device, AESParams, m_channelLayout.Count(), &m_pcm, config, format.m_sampleRate == dmixRate && !m_passthrough)) { CLog::Log(LOGERROR, "CAESinkALSA::Initialize - failed to initialize device \"%s\"", device.c_str()); snd_config_delete(config); return false; } /* get the actual device name that was used */ device = snd_pcm_name(m_pcm); m_device = device; CLog::Log(LOGINFO, "CAESinkALSA::Initialize - Opened device \"%s\"", device.c_str()); /* free the sound config */ snd_config_delete(config); if (!InitializeHW(format) || !InitializeSW(format)) return false; snd_pcm_nonblock(m_pcm, 1); snd_pcm_prepare (m_pcm); m_format = format; m_formatSampleRateMul = 1.0 / (double)m_format.m_sampleRate; return true; }