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 ); }
/** * Write the info for device dev into the buffer pointed to by info. * * @return The number of bytes used. */ static int ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo * info) { char *any = (char *) &info[1]; int len = 0, total_len = 0; info->deviceid = dev->id; info->use = GetDeviceUse(dev, &info->attachment); info->num_classes = 0; info->name_len = strlen(dev->name); info->enabled = dev->enabled; total_len = sizeof(xXIDeviceInfo); len = pad_to_int32(info->name_len); memset(any, 0, len); strncpy(any, dev->name, info->name_len); any += len; total_len += len; total_len += ListDeviceClasses(client, dev, any, &info->num_classes); return total_len; }
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; }
/** * Send the current state of the device hierarchy to all clients. */ void XISendDeviceHierarchyEvent(int flags[MAXDEVICES]) { xXIHierarchyEvent *ev; xXIHierarchyInfo *info; DeviceIntRec dummyDev; DeviceIntPtr dev; int i; if (!flags) return; ev = calloc(1, sizeof(xXIHierarchyEvent) + MAXDEVICES * sizeof(xXIHierarchyInfo)); if (!ev) return; ev->type = GenericEvent; ev->extension = IReqCode; ev->evtype = XI_HierarchyChanged; ev->time = GetTimeInMillis(); ev->flags = 0; ev->num_info = inputInfo.numDevices; info = (xXIHierarchyInfo*)&ev[1]; for (dev = inputInfo.devices; dev; dev = dev->next) { info->deviceid = dev->id; info->enabled = dev->enabled; info->use = GetDeviceUse(dev, &info->attachment); info->flags = flags[dev->id]; ev->flags |= info->flags; info++; } for (dev = inputInfo.off_devices; dev; dev = dev->next) { info->deviceid = dev->id; info->enabled = dev->enabled; info->use = GetDeviceUse(dev, &info->attachment); info->flags = flags[dev->id]; ev->flags |= info->flags; info++; } for (i = 0; i < MAXDEVICES; i++) { if (flags[i] & (XIMasterRemoved | XISlaveRemoved)) { info->deviceid = i; info->enabled = FALSE; info->flags = flags[i]; info->use = 0; ev->flags |= info->flags; ev->num_info++; info++; } } ev->length = bytes_to_int32(ev->num_info * sizeof(xXIHierarchyInfo)); memset(&dummyDev, 0, sizeof(dummyDev)); dummyDev.id = XIAllDevices; dummyDev.type = SLAVE; SendEventToAllWindows(&dummyDev, (XI_HierarchyChangedMask >> 8), (xEvent*)ev, 1); free(ev); }