aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2023-04-26 17:33:41 -0700
committerChris Robinson <[email protected]>2023-04-26 17:33:41 -0700
commite3d5c9f69cba4db2b5d4c0512a1132a83d3ce5d4 (patch)
treeefa826a175ff47a2e6c5a0bc0c67270011054170
parentaefc514ef6d1ab94ec595f5042dcbb3107f77dc9 (diff)
Print CoreAudio errors as FourCC codes when possible
-rw-r--r--alc/backends/coreaudio.cpp101
1 files changed, 58 insertions, 43 deletions
diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp
index 6a8003d2..d11bcf6f 100644
--- a/alc/backends/coreaudio.cpp
+++ b/alc/backends/coreaudio.cpp
@@ -55,6 +55,27 @@ namespace {
constexpr auto OutputElement = 0;
constexpr auto InputElement = 1;
+struct FourCCPrinter {
+ char mString[sizeof(UInt32) + 1]{};
+
+ constexpr FourCCPrinter(UInt32 code) noexcept
+ {
+ for(size_t i{0};i < sizeof(UInt32);++i)
+ {
+ const auto ch = static_cast<char>(code & 0xff);
+ /* If this breaks early it'll leave the first byte null, to get
+ * read as a 0-length string.
+ */
+ if(ch <= 0x1f || ch >= 0x7f)
+ break;
+ mString[sizeof(UInt32)-1-i] = ch;
+ code >>= 8;
+ }
+ }
+
+ constexpr const char *c_str() const noexcept { return mString; }
+};
+
#if CAN_ENUMERATE
struct DeviceEntry {
AudioDeviceID mId;
@@ -148,7 +169,8 @@ UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture)
&propSize);
if(err)
{
- ERR("kAudioDevicePropertyStreamConfiguration size query failed: %u\n", err);
+ ERR("kAudioDevicePropertyStreamConfiguration size query failed: '%s' (%u)\n",
+ FourCCPrinter{err}.c_str(), err);
return 0;
}
@@ -159,7 +181,8 @@ UInt32 GetDeviceChannelCount(AudioDeviceID devId, bool isCapture)
buflist);
if(err)
{
- ERR("kAudioDevicePropertyStreamConfiguration query failed: %u\n", err);
+ ERR("kAudioDevicePropertyStreamConfiguration query failed: '%s' (%u)\n",
+ FourCCPrinter{err}.c_str(), err);
return 0;
}
@@ -183,7 +206,7 @@ void EnumerateDevices(std::vector<DeviceEntry> &list, bool isCapture)
auto devIds = std::vector<AudioDeviceID>(propSize/sizeof(AudioDeviceID), kAudioDeviceUnknown);
if(auto err = GetHwProperty(kAudioHardwarePropertyDevices, propSize, devIds.data()))
{
- ERR("Failed to get device list: %u\n", err);
+ ERR("Failed to get device list: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
return;
}
@@ -261,13 +284,6 @@ struct CoreAudioPlayback final : public BackendBase {
OSStatus MixerProc(AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData) noexcept;
- static OSStatus MixerProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
- AudioBufferList *ioData) noexcept
- {
- return static_cast<CoreAudioPlayback*>(inRefCon)->MixerProc(ioActionFlags, inTimeStamp,
- inBusNumber, inNumberFrames, ioData);
- }
void open(const char *name) override;
bool reset() override;
@@ -352,7 +368,7 @@ void CoreAudioPlayback::open(const char *name)
OSStatus err{AudioComponentInstanceNew(comp, &audioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::NoDevice,
- "Could not create component instance: %u", err};
+ "Could not create component instance: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
#if CAN_ENUMERATE
if(audioDevice != kAudioDeviceUnknown)
@@ -363,7 +379,7 @@ void CoreAudioPlayback::open(const char *name)
err = AudioUnitInitialize(audioUnit);
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
- "Could not initialize audio unit: %u", err};
+ "Could not initialize audio unit: '%s' (%u)", 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.
@@ -399,9 +415,7 @@ void CoreAudioPlayback::open(const char *name)
ERR("Failed to get audio device type: %u\n", err);
else
{
- TRACE("Got device type '%c%c%c%c'\n", static_cast<char>((type>>24)&0xff),
- static_cast<char>((type>>16)&0xff), static_cast<char>((type>>8)&0xff),
- static_cast<char>(type&0xff));
+ TRACE("Got device type '%s'\n", FourCCPrinter{type}.c_str());
mDevice->Flags.set(DirectEar, (type == kIOAudioOutputPortSubTypeHeadphones));
}
}
@@ -415,7 +429,7 @@ bool CoreAudioPlayback::reset()
{
OSStatus err{AudioUnitUninitialize(mAudioUnit)};
if(err != noErr)
- ERR("-- AudioUnitUninitialize failed.\n");
+ ERR("AudioUnitUninitialize failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
/* retrieve default output unit's properties (output side) */
AudioStreamBasicDescription streamFormat{};
@@ -424,7 +438,8 @@ bool CoreAudioPlayback::reset()
OutputElement, &streamFormat, &size);
if(err != noErr || size != sizeof(streamFormat))
{
- ERR("AudioUnitGetProperty failed\n");
+ ERR("AudioUnitGetProperty(StreamFormat) failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(),
+ err);
return false;
}
@@ -491,7 +506,8 @@ bool CoreAudioPlayback::reset()
OutputElement, &streamFormat, sizeof(streamFormat));
if(err != noErr)
{
- ERR("AudioUnitSetProperty failed\n");
+ ERR("AudioUnitSetProperty(StreamFormat) failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(),
+ err);
return false;
}
@@ -500,14 +516,16 @@ bool CoreAudioPlayback::reset()
/* setup callback */
mFrameSize = mDevice->frameSizeFromFmt();
AURenderCallbackStruct input{};
- input.inputProc = CoreAudioPlayback::MixerProcC;
+ input.inputProc = [](void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept
+ { return static_cast<CoreAudioPlayback*>(inRefCon)->MixerProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); };
input.inputProcRefCon = this;
err = AudioUnitSetProperty(mAudioUnit, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, OutputElement, &input, sizeof(AURenderCallbackStruct));
if(err != noErr)
{
- ERR("AudioUnitSetProperty failed\n");
+ ERR("AudioUnitSetProperty(SetRenderCallback) failed: '%s' (%u)\n",
+ FourCCPrinter{err}.c_str(), err);
return false;
}
@@ -515,7 +533,7 @@ bool CoreAudioPlayback::reset()
err = AudioUnitInitialize(mAudioUnit);
if(err != noErr)
{
- ERR("AudioUnitInitialize failed\n");
+ ERR("AudioUnitInitialize failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
return false;
}
@@ -527,14 +545,14 @@ void CoreAudioPlayback::start()
const OSStatus err{AudioOutputUnitStart(mAudioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
- "AudioOutputUnitStart failed: %d", err};
+ "AudioOutputUnitStart failed: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
}
void CoreAudioPlayback::stop()
{
OSStatus err{AudioOutputUnitStop(mAudioUnit)};
if(err != noErr)
- ERR("AudioOutputUnitStop failed\n");
+ ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
}
@@ -545,13 +563,6 @@ struct CoreAudioCapture final : public BackendBase {
OSStatus RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
UInt32 inNumberFrames, AudioBufferList *ioData) noexcept;
- static OSStatus RecordProcC(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames,
- AudioBufferList *ioData) noexcept
- {
- return static_cast<CoreAudioCapture*>(inRefCon)->RecordProc(ioActionFlags, inTimeStamp,
- inBusNumber, inNumberFrames, ioData);
- }
void open(const char *name) override;
void start() override;
@@ -599,7 +610,7 @@ OSStatus CoreAudioCapture::RecordProc(AudioUnitRenderActionFlags *ioActionFlags,
inNumberFrames, &audiobuf.list)};
if(err != noErr)
{
- ERR("AudioUnitRender capture error: %d\n", err);
+ ERR("AudioUnitRender capture error: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
return err;
}
@@ -658,7 +669,7 @@ void CoreAudioCapture::open(const char *name)
OSStatus err{AudioComponentInstanceNew(comp, &mAudioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::NoDevice,
- "Could not create component instance: %u", err};
+ "Could not create component instance: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
// Turn off AudioUnit output
UInt32 enableIO{0};
@@ -666,7 +677,8 @@ void CoreAudioCapture::open(const char *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: %u", err};
+ "Could not disable audio unit output property: '%s' (%u)", FourCCPrinter{err}.c_str(),
+ err};
// Turn on AudioUnit input
enableIO = 1;
@@ -674,7 +686,8 @@ void CoreAudioCapture::open(const char *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: %u", err};
+ "Could not enable audio unit input property: '%s' (%u)", FourCCPrinter{err}.c_str(),
+ err};
#if CAN_ENUMERATE
if(audioDevice != kAudioDeviceUnknown)
@@ -684,14 +697,15 @@ void CoreAudioCapture::open(const char *name)
// set capture callback
AURenderCallbackStruct input{};
- input.inputProc = CoreAudioCapture::RecordProcC;
+ input.inputProc = [](void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) noexcept
+ { return static_cast<CoreAudioCapture*>(inRefCon)->RecordProc(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); };
input.inputProcRefCon = this;
err = AudioUnitSetProperty(mAudioUnit, kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global, InputElement, &input, sizeof(AURenderCallbackStruct));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
- "Could not set capture callback: %u", err};
+ "Could not set capture callback: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
// Disable buffer allocation for capture
UInt32 flag{0};
@@ -699,13 +713,14 @@ void CoreAudioCapture::open(const char *name)
kAudioUnitScope_Output, InputElement, &flag, sizeof(flag));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
- "Could not disable buffer allocation property: %u", err};
+ "Could not disable buffer allocation property: '%s' (%u)", 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: %u", err};
+ "Could not initialize audio unit: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
// Get the hardware format
AudioStreamBasicDescription hardwareFormat{};
@@ -714,7 +729,7 @@ void CoreAudioCapture::open(const char *name)
InputElement, &hardwareFormat, &propertySize);
if(err != noErr || propertySize != sizeof(hardwareFormat))
throw al::backend_exception{al::backend_error::DeviceError,
- "Could not get input format: %u", err};
+ "Could not get input format: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
// Set up the requested format description
AudioStreamBasicDescription requestedFormat{};
@@ -795,7 +810,7 @@ void CoreAudioCapture::open(const char *name)
InputElement, &outputFormat, sizeof(outputFormat));
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
- "Could not set input format: %u", err};
+ "Could not set input format: '%s' (%u)", 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.
@@ -814,7 +829,7 @@ void CoreAudioCapture::open(const char *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: %u", err};
+ "Could not get input frame count: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
mCaptureData.resize(outputFrameCount * mFrameSize);
@@ -852,14 +867,14 @@ void CoreAudioCapture::start()
OSStatus err{AudioOutputUnitStart(mAudioUnit)};
if(err != noErr)
throw al::backend_exception{al::backend_error::DeviceError,
- "AudioOutputUnitStart failed: %d", err};
+ "AudioOutputUnitStart failed: '%s' (%u)", FourCCPrinter{err}.c_str(), err};
}
void CoreAudioCapture::stop()
{
OSStatus err{AudioOutputUnitStop(mAudioUnit)};
if(err != noErr)
- ERR("AudioOutputUnitStop failed\n");
+ ERR("AudioOutputUnitStop failed: '%s' (%u)\n", FourCCPrinter{err}.c_str(), err);
}
void CoreAudioCapture::captureSamples(al::byte *buffer, uint samples)