Commit 28a00472 authored by Max Kellermann's avatar Max Kellermann

apple/Throw: new helper library replacing osx_os_status_to_cstring()

parent 8d540737
/*
* Copyright 2020 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Throw.hxx"
#include "ErrorRef.hxx"
#include "StringRef.hxx"
#include <stdexcept>
namespace Apple {
void
ThrowOSStatus(OSStatus status)
{
const Apple::ErrorRef cferr(nullptr, kCFErrorDomainOSStatus,
status, nullptr);
const Apple::StringRef cfstr(cferr.CopyDescription());
char msg[1024];
if (!cfstr.GetCString(msg, sizeof(msg)))
throw std::runtime_error("Unknown OSStatus");
throw std::runtime_error(msg);
}
void
ThrowOSStatus(OSStatus status, const char *_msg)
{
const Apple::ErrorRef cferr(nullptr, kCFErrorDomainOSStatus,
status, nullptr);
const Apple::StringRef cfstr(cferr.CopyDescription());
char msg[1024];
strcpy(msg, _msg);
size_t length = strlen(msg);
cfstr.GetCString(msg + length, sizeof(msg) - length);
throw std::runtime_error(msg);
}
} // namespace Apple
/*
* Copyright 2020 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef APPLE_THROW_HXX
#define APPLE_THROW_HXX
#include <CoreFoundation/CFBase.h>
namespace Apple {
void
ThrowOSStatus(OSStatus status);
void
ThrowOSStatus(OSStatus status, const char *msg);
} // namespace Apple
#endif
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include "config.h" #include "config.h"
#include "OSXOutputPlugin.hxx" #include "OSXOutputPlugin.hxx"
#include "apple/ErrorRef.hxx"
#include "apple/StringRef.hxx" #include "apple/StringRef.hxx"
#include "apple/Throw.hxx"
#include "../OutputAPI.hxx" #include "../OutputAPI.hxx"
#include "mixer/MixerList.hxx" #include "mixer/MixerList.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
...@@ -109,17 +109,6 @@ private: ...@@ -109,17 +109,6 @@ private:
static constexpr Domain osx_output_domain("osx_output"); static constexpr Domain osx_output_domain("osx_output");
static void
osx_os_status_to_cstring(OSStatus status, char *str, size_t size)
{
Apple::ErrorRef cferr(nullptr, kCFErrorDomainOSStatus, status, nullptr);
const Apple::StringRef cfstr(cferr.CopyDescription());
if (!cfstr.GetCString(str, size)) {
/* conversion failed, return empty string */
*str = '\0';
}
}
static bool static bool
osx_output_test_default_device() osx_output_test_default_device()
{ {
...@@ -209,11 +198,8 @@ OSXOutput::GetVolume() ...@@ -209,11 +198,8 @@ OSXOutput::GetVolume()
&size, &size,
&vol); &vol);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status);
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("unable to get volume: %s", errormsg);
}
return static_cast<int>(vol * 100.0); return static_cast<int>(vol * 100.0);
} }
...@@ -235,12 +221,8 @@ OSXOutput::SetVolume(unsigned new_volume) ...@@ -235,12 +221,8 @@ OSXOutput::SetVolume(unsigned new_volume)
size, size,
&vol); &vol);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status);
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError( "unable to set new volume %u: %s",
new_volume, errormsg);
}
} }
static void static void
...@@ -304,12 +286,9 @@ osx_output_set_channel_map(OSXOutput *oo) ...@@ -304,12 +286,9 @@ osx_output_set_channel_map(OSXOutput *oo)
0, 0,
&desc, &desc,
&size); &size);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status,
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg)); "unable to get number of output device channels");
throw FormatRuntimeError("%s: unable to get number of output device channels: %s",
oo->device_name, errormsg);
}
UInt32 num_channels = desc.mChannelsPerFrame; UInt32 num_channels = desc.mChannelsPerFrame;
std::unique_ptr<SInt32[]> channel_map(new SInt32[num_channels]); std::unique_ptr<SInt32[]> channel_map(new SInt32[num_channels]);
...@@ -325,11 +304,8 @@ osx_output_set_channel_map(OSXOutput *oo) ...@@ -325,11 +304,8 @@ osx_output_set_channel_map(OSXOutput *oo)
0, 0,
channel_map.get(), channel_map.get(),
size); size);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status, "unable to set channel map");
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("%s: unable to set channel map: %s", oo->device_name, errormsg);
}
} }
...@@ -639,12 +615,8 @@ osx_output_set_device(OSXOutput *oo) ...@@ -639,12 +615,8 @@ osx_output_set_device(OSXOutput *oo)
status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&aopa_hw_devices, 0, nullptr, &size); &aopa_hw_devices, 0, nullptr, &size);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status);
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("Unable to determine number of OS X audio devices: %s",
errormsg);
}
/* what are the available audio device IDs? */ /* what are the available audio device IDs? */
numdevices = size / sizeof(AudioDeviceID); numdevices = size / sizeof(AudioDeviceID);
...@@ -652,12 +624,8 @@ osx_output_set_device(OSXOutput *oo) ...@@ -652,12 +624,8 @@ osx_output_set_device(OSXOutput *oo)
status = AudioObjectGetPropertyData(kAudioObjectSystemObject, status = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&aopa_hw_devices, 0, nullptr, &aopa_hw_devices, 0, nullptr,
&size, deviceids.get()); &size, deviceids.get());
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status);
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("Unable to determine OS X audio device IDs: %s",
errormsg);
}
/* which audio device matches oo->device_name? */ /* which audio device matches oo->device_name? */
static constexpr AudioObjectPropertyAddress aopa_name{ static constexpr AudioObjectPropertyAddress aopa_name{
...@@ -700,12 +668,9 @@ osx_output_set_device(OSXOutput *oo) ...@@ -700,12 +668,9 @@ osx_output_set_device(OSXOutput *oo)
0, 0,
&(deviceids[i]), &(deviceids[i]),
sizeof(AudioDeviceID)); sizeof(AudioDeviceID));
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status,
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg)); "Unable to set OS X audio output device");
throw FormatRuntimeError("Unable to set OS X audio output device: %s",
errormsg);
}
oo->dev_id = deviceids[i]; oo->dev_id = deviceids[i];
FormatDebug(osx_output_domain, FormatDebug(osx_output_domain,
...@@ -756,12 +721,9 @@ OSXOutput::Enable() ...@@ -756,12 +721,9 @@ OSXOutput::Enable()
throw std::runtime_error("Error finding OS X component"); throw std::runtime_error("Error finding OS X component");
OSStatus status = AudioComponentInstanceNew(comp, &au); OSStatus status = AudioComponentInstanceNew(comp, &au);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status, "Unable to open OS X component");
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("Unable to open OS X component: %s",
errormsg);
}
#ifdef ENABLE_DSD #ifdef ENABLE_DSD
pcm_export.Construct(); pcm_export.Construct();
#endif #endif
...@@ -881,21 +843,13 @@ OSXOutput::Open(AudioFormat &audio_format) ...@@ -881,21 +843,13 @@ OSXOutput::Open(AudioFormat &audio_format)
} }
status = AudioUnitInitialize(au); status = AudioUnitInitialize(au);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status, "Unable to initialize OS X audio unit");
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("Unable to initialize OS X audio unit: %s",
errormsg);
}
UInt32 buffer_frame_size = 1; UInt32 buffer_frame_size = 1;
status = osx_output_set_buffer_size(au, asbd, &buffer_frame_size); status = osx_output_set_buffer_size(au, asbd, &buffer_frame_size);
if (status != noErr) { if (status != noErr)
char errormsg[1024]; Apple::ThrowOSStatus(status, "Unable to set frame size");
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("Unable to set frame size: %s",
errormsg);
}
size_t ring_buffer_size = std::max<size_t>(buffer_frame_size, size_t ring_buffer_size = std::max<size_t>(buffer_frame_size,
MPD_OSX_BUFFER_TIME_MS * audio_format.GetFrameSize() * audio_format.sample_rate / 1000); MPD_OSX_BUFFER_TIME_MS * audio_format.GetFrameSize() * audio_format.sample_rate / 1000);
...@@ -910,13 +864,9 @@ OSXOutput::Open(AudioFormat &audio_format) ...@@ -910,13 +864,9 @@ OSXOutput::Open(AudioFormat &audio_format)
ring_buffer = new boost::lockfree::spsc_queue<uint8_t>(ring_buffer_size); ring_buffer = new boost::lockfree::spsc_queue<uint8_t>(ring_buffer_size);
status = AudioOutputUnitStart(au); status = AudioOutputUnitStart(au);
if (status != 0) { if (status != 0)
AudioUnitUninitialize(au); Apple::ThrowOSStatus(status, "Unable to start audio output");
char errormsg[1024];
osx_os_status_to_cstring(status, errormsg, sizeof(errormsg));
throw FormatRuntimeError("Unable to start audio output: %s",
errormsg);
}
pause = false; pause = false;
} }
......
...@@ -73,7 +73,10 @@ if enable_oss ...@@ -73,7 +73,10 @@ if enable_oss
endif endif
if is_darwin if is_darwin
output_plugins_sources += 'OSXOutputPlugin.cxx' output_plugins_sources += [
'OSXOutputPlugin.cxx',
'../../apple/Throw.cxx',
]
audiounit_dep = declare_dependency( audiounit_dep = declare_dependency(
link_args: [ link_args: [
'-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreServices', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreServices',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment