update OpenAL-Soft to 1.24.3.

This commit is contained in:
Sasha Szpakowski
2025-05-03 12:51:37 -03:00
parent 375c6f88cd
commit 5e4f3241ac
322 changed files with 54386 additions and 12885 deletions
+171 -100
View File
@@ -24,7 +24,9 @@
#include <cinttypes>
#include <cmath>
#include <functional>
#include <memory>
#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -32,13 +34,13 @@
#include <string.h>
#include <unistd.h>
#include <vector>
#include <optional>
#include "alnumeric.h"
#include "alstring.h"
#include "core/converter.h"
#include "core/device.h"
#include "core/logging.h"
#include "fmt/core.h"
#include "ringbuffer.h"
#include <AudioUnit/AudioUnit.h>
@@ -56,10 +58,40 @@ namespace {
constexpr auto OutputElement = 0;
constexpr auto InputElement = 1;
// These following arrays should always be defined in ascending AudioChannelLabel value order
constexpr std::array<AudioChannelLabel, 1> MonoChanMap { kAudioChannelLabel_Mono };
constexpr std::array<AudioChannelLabel, 2> StereoChanMap { kAudioChannelLabel_Left, kAudioChannelLabel_Right};
constexpr std::array<AudioChannelLabel, 4> QuadChanMap {
kAudioChannelLabel_Left, kAudioChannelLabel_Right,
kAudioChannelLabel_LeftSurround, kAudioChannelLabel_RightSurround
};
constexpr std::array<AudioChannelLabel, 6> X51ChanMap {
kAudioChannelLabel_Left, kAudioChannelLabel_Right,
kAudioChannelLabel_Center, kAudioChannelLabel_LFEScreen,
kAudioChannelLabel_LeftSurround, kAudioChannelLabel_RightSurround
};
constexpr std::array<AudioChannelLabel, 6> X51RearChanMap {
kAudioChannelLabel_Left, kAudioChannelLabel_Right,
kAudioChannelLabel_Center, kAudioChannelLabel_LFEScreen,
kAudioChannelLabel_RearSurroundRight, kAudioChannelLabel_RearSurroundLeft
};
constexpr std::array<AudioChannelLabel, 7> X61ChanMap {
kAudioChannelLabel_Left, kAudioChannelLabel_Right,
kAudioChannelLabel_Center, kAudioChannelLabel_LFEScreen,
kAudioChannelLabel_CenterSurround,
kAudioChannelLabel_RearSurroundRight, kAudioChannelLabel_RearSurroundLeft
};
constexpr std::array<AudioChannelLabel, 8> X71ChanMap {
kAudioChannelLabel_Left, kAudioChannelLabel_Right,
kAudioChannelLabel_Center, kAudioChannelLabel_LFEScreen,
kAudioChannelLabel_LeftSurround, kAudioChannelLabel_RightSurround,
kAudioChannelLabel_LeftCenter, kAudioChannelLabel_RightCenter
};
struct FourCCPrinter {
char mString[sizeof(UInt32) + 1]{};
constexpr FourCCPrinter(UInt32 code) noexcept
explicit constexpr FourCCPrinter(UInt32 code) noexcept
{
for(size_t i{0};i < sizeof(UInt32);++i)
{
@@ -73,7 +105,7 @@ struct FourCCPrinter {
code >>= 8;
}
}
constexpr FourCCPrinter(int code) noexcept : FourCCPrinter{static_cast<UInt32>(code)} { }
explicit constexpr FourCCPrinter(OSStatus code) noexcept : FourCCPrinter{static_cast<UInt32>(code)} { }
constexpr const char *c_str() const noexcept { return mString; }
};
@@ -159,19 +191,19 @@ std::string GetDeviceName(AudioDeviceID devId)
/* Clear extraneous nul chars that may have been written with the name
* string, and return it.
*/
while(!devname.back())
while(!devname.empty() && !devname.back())
devname.pop_back();
return devname;
}
UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture)
auto GetDeviceChannelCount(AudioDeviceID devId, bool isCapture) -> UInt32
{
UInt32 propSize{};
auto propSize = UInt32{};
auto err = GetDevPropertySize(devId, kAudioDevicePropertyStreamConfiguration, isCapture, 0,
&propSize);
if(err)
{
ERR("kAudioDevicePropertyStreamConfiguration size query failed: '%s' (%u)\n",
ERR("kAudioDevicePropertyStreamConfiguration size query failed: '{}' ({})",
FourCCPrinter{err}.c_str(), err);
return 0;
}
@@ -183,15 +215,14 @@ UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture)
buflist);
if(err)
{
ERR("kAudioDevicePropertyStreamConfiguration query failed: '%s' (%u)\n",
ERR("kAudioDevicePropertyStreamConfiguration query failed: '{}' ({})",
FourCCPrinter{err}.c_str(), err);
return 0;
}
UInt32 numChannels{0};
auto numChannels = UInt32{0};
for(size_t i{0};i < buflist->mNumberBuffers;++i)
numChannels += buflist->mBuffers[i].mNumberChannels;
return numChannels;
}
@@ -201,14 +232,14 @@ void EnumerateDevices(std::vector<DeviceEntry> &list, bool isCapture)
UInt32 propSize{};
if(auto err = GetHwPropertySize(kAudioHardwarePropertyDevices, &propSize))
{
ERR("Failed to get device list size: %u\n", err);
ERR("Failed to get device list size: {}", err);
return;
}
auto devIds = std::vector<AudioDeviceID>(propSize/sizeof(AudioDeviceID), kAudioDeviceUnknown);
if(auto err = GetHwProperty(kAudioHardwarePropertyDevices, propSize, devIds.data()))
{
ERR("Failed to get device list: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
ERR("Failed to get device list: '{}' ({})", FourCCPrinter{err}.c_str(), err);
return;
}
@@ -223,7 +254,7 @@ void EnumerateDevices(std::vector<DeviceEntry> &list, bool isCapture)
{
newdevs.emplace_back(DeviceEntry{defaultId, GetDeviceName(defaultId)});
const auto &entry = newdevs.back();
TRACE("Got device: %s = ID %u\n", entry.mName.c_str(), entry.mId);
TRACE("Got device: {} = ID {}", entry.mName, entry.mId);
}
for(const AudioDeviceID devId : devIds)
{
@@ -240,7 +271,7 @@ void EnumerateDevices(std::vector<DeviceEntry> &list, bool isCapture)
{
newdevs.emplace_back(DeviceEntry{devId, GetDeviceName(devId)});
const auto &entry = newdevs.back();
TRACE("Got device: %s = ID %u\n", entry.mName.c_str(), entry.mId);
TRACE("Got device: {} = ID {}", entry.mName, entry.mId);
}
}
@@ -255,14 +286,12 @@ void EnumerateDevices(std::vector<DeviceEntry> &list, bool isCapture)
{ return entry.mName == curitem->mName; };
if(std::find_if(newdevs.begin(), curitem, check_match) != curitem)
{
std::string name{curitem->mName};
size_t count{1};
auto name = std::string{curitem->mName};
auto count = 1_uz;
auto check_name = [&name](const DeviceEntry &entry) -> bool
{ return entry.mName == name; };
do {
name = curitem->mName;
name += " #";
name += std::to_string(++count);
name = fmt::format("{} #{}", curitem->mName, ++count);
} while(std::find_if(newdevs.begin(), curitem, check_name) != curitem);
curitem->mName = std::move(name);
}
@@ -277,18 +306,18 @@ struct DeviceHelper {
DeviceHelper()
{
AudioObjectPropertyAddress addr{kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain};
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
OSStatus status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &addr, DeviceListenerProc, nil);
if (status != noErr)
ERR("AudioObjectAddPropertyListener fail: %d", status);
ERR("AudioObjectAddPropertyListener fail: {}", status);
}
~DeviceHelper()
{
AudioObjectPropertyAddress addr{kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain};
kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
OSStatus status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &addr, DeviceListenerProc, nil);
if (status != noErr)
ERR("AudioObjectRemovePropertyListener fail: %d", status);
ERR("AudioObjectRemovePropertyListener fail: {}", status);
}
static OSStatus DeviceListenerProc(AudioObjectID /*inObjectID*/, UInt32 inNumberAddresses,
@@ -322,7 +351,7 @@ static constexpr char ca_device[] = "CoreAudio Default";
struct CoreAudioPlayback final : public BackendBase {
CoreAudioPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
explicit CoreAudioPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
~CoreAudioPlayback() override;
OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags,
@@ -377,7 +406,7 @@ void CoreAudioPlayback::open(std::string_view name)
auto devmatch = std::find_if(PlaybackList.cbegin(), PlaybackList.cend(), find_name);
if(devmatch == PlaybackList.cend())
throw al::backend_exception{al::backend_error::NoDevice,
"Device name \"%.*s\" not found", al::sizei(name), name.data()};
"Device name \"{}\" not found", name};
audioDevice = devmatch->mId;
}
@@ -385,8 +414,8 @@ void CoreAudioPlayback::open(std::string_view name)
if(name.empty())
name = ca_device;
else if(name != ca_device)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
al::sizei(name), name.data()};
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"{}\" not found",
name};
#endif
/* open the default output unit */
@@ -410,7 +439,7 @@ void CoreAudioPlayback::open(std::string_view name)
OSStatus err{AudioComponentInstanceNew(comp, &audioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::NoDevice,
"Could not create component instance: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not create component instance: '{}' ({})", FourCCPrinter{err}.c_str(), err};
#if CAN_ENUMERATE
if(audioDevice != kAudioDeviceUnknown)
@@ -421,7 +450,7 @@ void CoreAudioPlayback::open(std::string_view name)
err = AudioUnitInitialize(audioUnit);
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not initialize audio unit: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not initialize audio unit: '{}' ({})", FourCCPrinter{err}.c_str(), err};
/* WARNING: I don't know if "valid" audio unit values are guaranteed to be
* non-0. If not, this logic is broken.
@@ -435,7 +464,7 @@ void CoreAudioPlayback::open(std::string_view name)
#if CAN_ENUMERATE
if(!name.empty())
mDevice->DeviceName = name;
mDeviceName = name;
else
{
UInt32 propSize{sizeof(audioDevice)};
@@ -444,8 +473,8 @@ void CoreAudioPlayback::open(std::string_view name)
kAudioUnitScope_Global, OutputElement, &audioDevice, &propSize);
std::string devname{GetDeviceName(audioDevice)};
if(!devname.empty()) mDevice->DeviceName = std::move(devname);
else mDevice->DeviceName = "Unknown Device Name";
if(!devname.empty()) mDeviceName = std::move(devname);
else mDeviceName = "Unknown Device Name";
}
if(audioDevice != kAudioDeviceUnknown)
@@ -454,16 +483,16 @@ void CoreAudioPlayback::open(std::string_view name)
err = GetDevProperty(audioDevice, kAudioDevicePropertyDataSource, false,
kAudioObjectPropertyElementMaster, sizeof(type), &type);
if(err != noErr)
ERR("Failed to get audio device type: %u\n", err);
WARN("Failed to get audio device type: '{}' ({})", FourCCPrinter{err}.c_str(), err);
else
{
TRACE("Got device type '%s'\n", FourCCPrinter{type}.c_str());
TRACE("Got device type '{}'", FourCCPrinter{type}.c_str());
mDevice->Flags.set(DirectEar, (type == kIOAudioOutputPortSubTypeHeadphones));
}
}
#else
mDevice->DeviceName = name;
mDeviceName = name;
#endif
}
@@ -471,7 +500,7 @@ bool CoreAudioPlayback::reset()
{
OSStatus err{AudioUnitUninitialize(mAudioUnit)};
if(err != noErr)
ERR("AudioUnitUninitialize failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
ERR("AudioUnitUninitialize failed: '{}' ({})", FourCCPrinter{err}.c_str(), err);
/* retrieve default output unit's properties (output side) */
AudioStreamBasicDescription streamFormat{};
@@ -480,33 +509,75 @@ bool CoreAudioPlayback::reset()
OutputElement, &streamFormat, &size);
if(err != noErr || size != sizeof(streamFormat))
{
ERR("AudioUnitGetProperty(StreamFormat) failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(),
ERR("AudioUnitGetProperty(StreamFormat) failed: '{}' ({})", FourCCPrinter{err}.c_str(),
err);
return false;
}
#if 0
TRACE("Output streamFormat of default output unit -\n");
TRACE(" streamFormat.mFramesPerPacket = %d\n", streamFormat.mFramesPerPacket);
TRACE(" streamFormat.mChannelsPerFrame = %d\n", streamFormat.mChannelsPerFrame);
TRACE(" streamFormat.mBitsPerChannel = %d\n", streamFormat.mBitsPerChannel);
TRACE(" streamFormat.mBytesPerPacket = %d\n", streamFormat.mBytesPerPacket);
TRACE(" streamFormat.mBytesPerFrame = %d\n", streamFormat.mBytesPerFrame);
TRACE(" streamFormat.mSampleRate = %5.0f\n", streamFormat.mSampleRate);
#endif
/* Use the sample rate from the output unit's current parameters, but reset
* everything else.
*/
if(mDevice->Frequency != streamFormat.mSampleRate)
if(mDevice->mSampleRate != streamFormat.mSampleRate)
{
mDevice->BufferSize = static_cast<uint>(mDevice->BufferSize*streamFormat.mSampleRate/
mDevice->Frequency + 0.5);
mDevice->Frequency = static_cast<uint>(streamFormat.mSampleRate);
mDevice->mBufferSize = static_cast<uint>(mDevice->mBufferSize*streamFormat.mSampleRate/
mDevice->mSampleRate + 0.5);
mDevice->mSampleRate = static_cast<uint>(streamFormat.mSampleRate);
}
/* FIXME: How to tell what channels are what in the output device, and how
* to specify what we're giving? e.g. 6.0 vs 5.1
struct ChannelMap {
DevFmtChannels fmt;
al::span<const AudioChannelLabel> map;
bool is_51rear;
};
static constexpr std::array<ChannelMap,7> chanmaps{{
{ DevFmtX71, X71ChanMap, false },
{ DevFmtX61, X61ChanMap, false },
{ DevFmtX51, X51ChanMap, false },
{ DevFmtX51, X51RearChanMap, true },
{ DevFmtQuad, QuadChanMap, false },
{ DevFmtStereo, StereoChanMap, false },
{ DevFmtMono, MonoChanMap, false }
}};
if(!mDevice->Flags.test(ChannelsRequest))
{
auto propSize = UInt32{};
auto writable = Boolean{};
err = AudioUnitGetPropertyInfo(mAudioUnit, kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output, OutputElement, &propSize, &writable);
if(err == noErr)
{
auto layout_data = std::make_unique<char[]>(propSize);
auto *layout = reinterpret_cast<AudioChannelLayout*>(layout_data.get());
err = AudioUnitGetProperty(mAudioUnit, kAudioUnitProperty_AudioChannelLayout,
kAudioUnitScope_Output, OutputElement, layout, &propSize);
if(err == noErr)
{
auto descs = al::span{std::data(layout->mChannelDescriptions),
layout->mNumberChannelDescriptions};
auto labels = std::vector<AudioChannelLayoutTag>(descs.size());
std::transform(descs.begin(), descs.end(), labels.begin(),
std::mem_fn(&AudioChannelDescription::mChannelLabel));
sort(labels.begin(), labels.end());
auto check_labels = [&labels](const ChannelMap &chanmap) -> bool
{
return std::includes(labels.begin(), labels.end(), chanmap.map.begin(),
chanmap.map.end());
};
auto chaniter = std::find_if(chanmaps.cbegin(), chanmaps.cend(), check_labels);
if(chaniter != chanmaps.cend())
mDevice->FmtChans = chaniter->fmt;
}
}
}
/* TODO: Also set kAudioUnitProperty_AudioChannelLayout according to the AL
* device's channel configuration.
*/
streamFormat.mChannelsPerFrame = mDevice->channelsFromFmt();
@@ -548,7 +619,7 @@ bool CoreAudioPlayback::reset()
OutputElement, &streamFormat, sizeof(streamFormat));
if(err != noErr)
{
ERR("AudioUnitSetProperty(StreamFormat) failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(),
ERR("AudioUnitSetProperty(StreamFormat) failed: '{}' ({})", FourCCPrinter{err}.c_str(),
err);
return false;
}
@@ -566,7 +637,7 @@ bool CoreAudioPlayback::reset()
kAudioUnitScope_Input, OutputElement, &input, sizeof(AURenderCallbackStruct));
if(err != noErr)
{
ERR("AudioUnitSetProperty(SetRenderCallback) failed: '%s' (%u)\n",
ERR("AudioUnitSetProperty(SetRenderCallback) failed: '{}' ({})",
FourCCPrinter{err}.c_str(), err);
return false;
}
@@ -575,7 +646,7 @@ bool CoreAudioPlayback::reset()
err = AudioUnitInitialize(mAudioUnit);
if(err != noErr)
{
ERR("AudioUnitInitialize failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
ERR("AudioUnitInitialize failed: '{}' ({})", FourCCPrinter{err}.c_str(), err);
return false;
}
@@ -587,19 +658,19 @@ void CoreAudioPlayback::start()
const OSStatus err{AudioOutputUnitStart(mAudioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"AudioOutputUnitStart failed: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"AudioOutputUnitStart failed: '{}' ({})", FourCCPrinter{err}.c_str(), err};
}
void CoreAudioPlayback::stop()
{
OSStatus err{AudioOutputUnitStop(mAudioUnit)};
if(err != noErr)
ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
ERR("AudioOutputUnitStop failed: '{}' ({})", FourCCPrinter{err}.c_str(), err);
}
struct CoreAudioCapture final : public BackendBase {
CoreAudioCapture(DeviceBase *device) noexcept : BackendBase{device} { }
explicit CoreAudioCapture(DeviceBase *device) noexcept : BackendBase{device} { }
~CoreAudioCapture() override;
OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
@@ -650,7 +721,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
inNumberFrames, &audiobuf.list)};
if(err != noErr)
{
ERR("AudioUnitRender capture error: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
ERR("AudioUnitRender capture error: '{}' ({})", FourCCPrinter{err}.c_str(), err);
return err;
}
@@ -676,7 +747,7 @@ void CoreAudioCapture::open(std::string_view name)
auto devmatch = std::find_if(CaptureList.cbegin(), CaptureList.cend(), find_name);
if(devmatch == CaptureList.cend())
throw al::backend_exception{al::backend_error::NoDevice,
"Device name \"%.*s\" not found", al::sizei(name), name.data()};
"Device name \"{}\" not found", name};
audioDevice = devmatch->mId;
}
@@ -684,8 +755,8 @@ void CoreAudioCapture::open(std::string_view name)
if(name.empty())
name = ca_device;
else if(name != ca_device)
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%.*s\" not found",
al::sizei(name), name.data()};
throw al::backend_exception{al::backend_error::NoDevice, "Device name \"{}\" not found",
name};
#endif
AudioComponentDescription desc{};
@@ -709,7 +780,7 @@ void CoreAudioCapture::open(std::string_view name)
OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::NoDevice,
"Could not create component instance: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not create component instance: '{}' ({})", FourCCPrinter{err}.c_str(), err};
// Turn off AudioUnit output
UInt32 enableIO{0};
@@ -717,7 +788,7 @@ void CoreAudioCapture::open(std::string_view name)
kAudioUnitScope_Output, OutputElement, &enableIO, sizeof(enableIO));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not disable audio unit output property: '%s' (%u)", FourCCPrinter{err}.c_str(),
"Could not disable audio unit output property: '{}' ({})", FourCCPrinter{err}.c_str(),
err};
// Turn on AudioUnit input
@@ -726,7 +797,7 @@ void CoreAudioCapture::open(std::string_view name)
kAudioUnitScope_Input, InputElement, &enableIO, sizeof(enableIO));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not enable audio unit input property: '%s' (%u)", FourCCPrinter{err}.c_str(),
"Could not enable audio unit input property: '{}' ({})", FourCCPrinter{err}.c_str(),
err};
#if CAN_ENUMERATE
@@ -745,7 +816,7 @@ void CoreAudioCapture::open(std::string_view name)
kAudioUnitScope_Global, InputElement, &input, sizeof(AURenderCallbackStruct));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not set capture callback: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not set capture callback: '{}' ({})", FourCCPrinter{err}.c_str(), err};
// Disable buffer allocation for capture
UInt32 flag{0};
@@ -753,14 +824,14 @@ void CoreAudioCapture::open(std::string_view name)
kAudioUnitScope_Output, InputElement, &flag, sizeof(flag));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not disable buffer allocation property: '%s' (%u)", FourCCPrinter{err}.c_str(),
"Could not disable buffer allocation property: '{}' ({})", FourCCPrinter{err}.c_str(),
err};
// Initialize the device
err = AudioUnitInitialize(mAudioUnit);
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not initialize audio unit: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not initialize audio unit: '{}' ({})", FourCCPrinter{err}.c_str(), err};
// Get the hardware format
AudioStreamBasicDescription hardwareFormat{};
@@ -769,7 +840,7 @@ void CoreAudioCapture::open(std::string_view name)
InputElement, &hardwareFormat, &propertySize);
if(err != noErr || propertySize != sizeof(hardwareFormat))
throw al::backend_exception{al::backend_error::DeviceError,
"Could not get input format: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not get input format: '{}' ({})", FourCCPrinter{err}.c_str(), err};
// Set up the requested format description
AudioStreamBasicDescription requestedFormat{};
@@ -822,15 +893,16 @@ void CoreAudioCapture::open(std::string_view name)
case DevFmtX61:
case DevFmtX71:
case DevFmtX714:
case DevFmtX7144:
case DevFmtX3D71:
case DevFmtAmbi3D:
throw al::backend_exception{al::backend_error::DeviceError, "%s not supported",
throw al::backend_exception{al::backend_error::DeviceError, "{} not supported",
DevFmtChannelsString(mDevice->FmtChans)};
}
requestedFormat.mBytesPerFrame = requestedFormat.mChannelsPerFrame * requestedFormat.mBitsPerChannel / 8;
requestedFormat.mBytesPerPacket = requestedFormat.mBytesPerFrame;
requestedFormat.mSampleRate = mDevice->Frequency;
requestedFormat.mSampleRate = mDevice->mSampleRate;
requestedFormat.mFormatID = kAudioFormatLinearPCM;
requestedFormat.mReserved = 0;
requestedFormat.mFramesPerPacket = 1;
@@ -850,18 +922,18 @@ void CoreAudioCapture::open(std::string_view name)
InputElement, &outputFormat, sizeof(outputFormat));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"Could not set input format: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not set input format: '{}' ({})", FourCCPrinter{err}.c_str(), err};
/* Calculate the minimum AudioUnit output format frame count for the pre-
* conversion ring buffer. Ensure at least 100ms for the total buffer.
*/
double srateScale{outputFormat.mSampleRate / mDevice->Frequency};
auto FrameCount64 = std::max(static_cast<uint64_t>(std::ceil(mDevice->BufferSize*srateScale)),
double srateScale{outputFormat.mSampleRate / mDevice->mSampleRate};
auto FrameCount64 = std::max(static_cast<uint64_t>(std::ceil(mDevice->mBufferSize*srateScale)),
static_cast<UInt32>(outputFormat.mSampleRate)/10_u64);
FrameCount64 += MaxResamplerPadding;
if(FrameCount64 > std::numeric_limits<int32_t>::max())
throw al::backend_exception{al::backend_error::DeviceError,
"Calculated frame count is too large: %" PRIu64, FrameCount64};
"Calculated frame count is too large: {}", FrameCount64};
UInt32 outputFrameCount{};
propertySize = sizeof(outputFrameCount);
@@ -869,7 +941,7 @@ void CoreAudioCapture::open(std::string_view name)
kAudioUnitScope_Global, OutputElement, &outputFrameCount, &propertySize);
if(err != noErr || propertySize != sizeof(outputFrameCount))
throw al::backend_exception{al::backend_error::DeviceError,
"Could not get input frame count: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"Could not get input frame count: '{}' ({})", FourCCPrinter{err}.c_str(), err};
mCaptureData.resize(outputFrameCount * mFrameSize);
@@ -877,14 +949,14 @@ void CoreAudioCapture::open(std::string_view name)
mRing = RingBuffer::Create(outputFrameCount, mFrameSize, false);
/* Set up sample converter if needed */
if(outputFormat.mSampleRate != mDevice->Frequency)
if(outputFormat.mSampleRate != mDevice->mSampleRate)
mConverter = SampleConverter::Create(mDevice->FmtType, mDevice->FmtType,
mFormat.mChannelsPerFrame, static_cast<uint>(hardwareFormat.mSampleRate),
mDevice->Frequency, Resampler::FastBSinc24);
mDevice->mSampleRate, Resampler::FastBSinc24);
#if CAN_ENUMERATE
if(!name.empty())
mDevice->DeviceName = name;
mDeviceName = name;
else
{
UInt32 propSize{sizeof(audioDevice)};
@@ -893,11 +965,11 @@ void CoreAudioCapture::open(std::string_view name)
kAudioUnitScope_Global, InputElement, &audioDevice, &propSize);
std::string devname{GetDeviceName(audioDevice)};
if(!devname.empty()) mDevice->DeviceName = std::move(devname);
else mDevice->DeviceName = "Unknown Device Name";
if(!devname.empty()) mDeviceName = std::move(devname);
else mDeviceName = "Unknown Device Name";
}
#else
mDevice->DeviceName = name;
mDeviceName = name;
#endif
}
@@ -907,14 +979,14 @@ void CoreAudioCapture::start()
OSStatus err{AudioOutputUnitStart(mAudioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
"AudioOutputUnitStart failed: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
"AudioOutputUnitStart failed: '{}' ({})", FourCCPrinter{err}.c_str(), err};
}
void CoreAudioCapture::stop()
{
OSStatus err{AudioOutputUnitStop(mAudioUnit)};
if(err != noErr)
ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
ERR("AudioOutputUnitStop failed: '{}' ({})", FourCCPrinter{err}.c_str(), err);
}
void CoreAudioCapture::captureSamples(std::byte *buffer, uint samples)
@@ -926,16 +998,16 @@ void CoreAudioCapture::captureSamples(std::byte *buffer, uint samples)
}
auto rec_vec = mRing->getReadVector();
const void *src0{rec_vec.first.buf};
auto src0len = static_cast<uint>(rec_vec.first.len);
const void *src0{rec_vec[0].buf};
auto src0len = static_cast<uint>(rec_vec[0].len);
uint got{mConverter->convert(&src0, &src0len, buffer, samples)};
size_t total_read{rec_vec.first.len - src0len};
if(got < samples && !src0len && rec_vec.second.len > 0)
size_t total_read{rec_vec[0].len - src0len};
if(got < samples && !src0len && rec_vec[1].len > 0)
{
const void *src1{rec_vec.second.buf};
auto src1len = static_cast<uint>(rec_vec.second.len);
const void *src1{rec_vec[1].buf};
auto src1len = static_cast<uint>(rec_vec[1].len);
got += mConverter->convert(&src1, &src1len, buffer + got*mFrameSize, samples-got);
total_read += rec_vec.second.len - src1len;
total_read += rec_vec[1].len - src1len;
}
mRing->readAdvance(total_read);
@@ -966,23 +1038,23 @@ bool CoreAudioBackendFactory::init()
bool CoreAudioBackendFactory::querySupport(BackendType type)
{ return type == BackendType::Playback || type == BackendType::Capture; }
std::string CoreAudioBackendFactory::probe(BackendType type)
auto CoreAudioBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
{
std::string outnames;
std::vector<std::string> outnames;
#if CAN_ENUMERATE
auto append_name = [&outnames](const DeviceEntry &entry) -> void
{
/* Includes null char. */
outnames.append(entry.mName.c_str(), entry.mName.length()+1);
};
{ outnames.emplace_back(entry.mName); };
switch(type)
{
case BackendType::Playback:
EnumerateDevices(PlaybackList, false);
outnames.reserve(PlaybackList.size());
std::for_each(PlaybackList.cbegin(), PlaybackList.cend(), append_name);
break;
case BackendType::Capture:
EnumerateDevices(CaptureList, true);
outnames.reserve(CaptureList.size());
std::for_each(CaptureList.cbegin(), CaptureList.cend(), append_name);
break;
}
@@ -993,8 +1065,7 @@ std::string CoreAudioBackendFactory::probe(BackendType type)
{
case BackendType::Playback:
case BackendType::Capture:
/* Includes null char. */
outnames.append(ca_device, sizeof(ca_device));
outnames.emplace_back(ca_device);
break;
}
#endif