Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Müller <nexyon@gmail.com>2021-03-14 14:46:47 +0300
committerJörg Müller <nexyon@gmail.com>2021-03-17 01:21:45 +0300
commit12c08ceee3b034e360824969ea4e1aaed4be2daf (patch)
tree022c4bd87118b19af6e8477593466a3e7c25d2a4
parentbc5798530663a9b3fec8df60feba510bd681c5ad (diff)
Audaspace: add support for CoreAudio on macOS
This adds CoreAudio as audio backend on macOS. CoreAudio is the standard audio API on macOS. Ref T86590
-rw-r--r--CMakeLists.txt7
-rw-r--r--build_files/cmake/config/blender_full.cmake3
-rw-r--r--build_files/cmake/config/blender_headless.cmake1
-rw-r--r--build_files/cmake/config/blender_lite.cmake1
-rw-r--r--build_files/cmake/config/blender_release.cmake3
-rw-r--r--build_files/cmake/config/bpy_module.cmake1
-rw-r--r--doc/doxygen/doxygen.intern.h3
-rw-r--r--extern/audaspace/CMakeLists.txt56
-rw-r--r--extern/audaspace/blender_config.cmake1
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp235
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioDevice.h100
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp127
-rw-r--r--extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h64
-rw-r--r--extern/audaspace/src/plugin/PluginManagerUnix.cpp.in5
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/CMakeLists.txt4
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/creator/creator_args.c2
18 files changed, 621 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 360667bca86..5f30b946aca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -300,6 +300,11 @@ option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.or
# Sound output
option(WITH_SDL "Enable SDL for sound and joystick support" ON)
option(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON)
+if(APPLE)
+ option(WITH_COREAUDIO "Enable CoreAudio for audio support on macOS" ON)
+else()
+ set(WITH_COREAUDIO OFF)
+endif()
if(NOT WIN32)
option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ON)
if(UNIX AND NOT APPLE)
@@ -685,6 +690,7 @@ if(NOT WITH_BLENDER AND NOT WITH_CYCLES_STANDALONE)
endif()
set_and_warn_dependency(WITH_AUDASPACE WITH_OPENAL OFF)
+set_and_warn_dependency(WITH_AUDASPACE WITH_COREAUDIO OFF)
set_and_warn_dependency(WITH_AUDASPACE WITH_JACK OFF)
set_and_warn_dependency(WITH_AUDASPACE WITH_PULSEAUDIO OFF)
set_and_warn_dependency(WITH_AUDASPACE WITH_WASAPI OFF)
@@ -1945,6 +1951,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_CODEC_AVI)
info_cfg_option(WITH_CODEC_FFMPEG)
info_cfg_option(WITH_CODEC_SNDFILE)
+ info_cfg_option(WITH_COREAUDIO)
info_cfg_option(WITH_JACK)
info_cfg_option(WITH_JACK_DYNLOAD)
info_cfg_option(WITH_OPENAL)
diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake
index 9c69c4a2cdf..7d8ca9ec98d 100644
--- a/build_files/cmake/config/blender_full.cmake
+++ b/build_files/cmake/config/blender_full.cmake
@@ -59,6 +59,9 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
# platform dependent options
+if(APPLE)
+ set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
+endif()
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/config/blender_headless.cmake b/build_files/cmake/config/blender_headless.cmake
index dd68fcfc5f5..72921c0e390 100644
--- a/build_files/cmake/config/blender_headless.cmake
+++ b/build_files/cmake/config/blender_headless.cmake
@@ -10,6 +10,7 @@ set(WITH_HEADLESS ON CACHE BOOL "" FORCE)
# disable audio, its possible some devs may want this but for now disable
# so the python module doesn't hold the audio device and loads quickly.
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
+set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake
index 7df7d064c54..f79bbe9d34b 100644
--- a/build_files/cmake/config/blender_lite.cmake
+++ b/build_files/cmake/config/blender_lite.cmake
@@ -16,6 +16,7 @@ set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)
set(WITH_COMPOSITOR OFF CACHE BOOL "" FORCE)
+set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_EMBREE OFF CACHE BOOL "" FORCE)
set(WITH_CYCLES_OSL OFF CACHE BOOL "" FORCE)
diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake
index 29101a2f31c..7dad6d6b886 100644
--- a/build_files/cmake/config/blender_release.cmake
+++ b/build_files/cmake/config/blender_release.cmake
@@ -63,6 +63,9 @@ set(CYCLES_CUDA_BINARIES_ARCH sm_30;sm_35;sm_37;sm_50;sm_52;sm_60;sm_61;sm_70;sm
set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
# platform dependent options
+if(APPLE)
+ set(WITH_COREAUDIO ON CACHE BOOL "" FORCE)
+endif()
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
diff --git a/build_files/cmake/config/bpy_module.cmake b/build_files/cmake/config/bpy_module.cmake
index eeb72f669ea..087fdd87649 100644
--- a/build_files/cmake/config/bpy_module.cmake
+++ b/build_files/cmake/config/bpy_module.cmake
@@ -15,6 +15,7 @@ set(WITH_PYTHON_INSTALL OFF CACHE BOOL "" FORCE)
# disable audio, its possible some devs may want this but for now disable
# so the python module doesn't hold the audio device and loads quickly.
set(WITH_AUDASPACE OFF CACHE BOOL "" FORCE)
+set(WITH_COREAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
diff --git a/doc/doxygen/doxygen.intern.h b/doc/doxygen/doxygen.intern.h
index 8a9bf54e301..b08b868a7e3 100644
--- a/doc/doxygen/doxygen.intern.h
+++ b/doc/doxygen/doxygen.intern.h
@@ -54,6 +54,9 @@
* \ingroup intern undoc
* \todo add to doxygen
*/
+/** \defgroup audcoreaudio Audaspace CoreAudio
+ * \ingroup audaspace
+ */
/** \defgroup audfx Audaspace FX
* \ingroup audaspace
*/
diff --git a/extern/audaspace/CMakeLists.txt b/extern/audaspace/CMakeLists.txt
index dc851961d47..f14cc4e7adf 100644
--- a/extern/audaspace/CMakeLists.txt
+++ b/extern/audaspace/CMakeLists.txt
@@ -284,7 +284,9 @@ if(AUDASPACE_STANDALONE)
option(WITH_PYTHON "Build With Python Library" TRUE)
option(WITH_SDL "Build With SDL" TRUE)
option(WITH_STRICT_DEPENDENCIES "Error and abort instead of warning if a library is not found." FALSE)
-
+ if(APPLE)
+ option(WITH_COREAUDIO "Build With CoreAudio" TRUE)
+ endif()
if(NOT WIN32 AND NOT APPLE)
option(WITH_PULSEAUDIO "Build With PulseAudio" TRUE)
endif()
@@ -298,7 +300,7 @@ if(AUDASPACE_STANDALONE)
endif()
if(AUDASPACE_STANDALONE)
- if(WIN32)
+ if(WIN32 OR APPLE)
set(DEFAULT_PLUGIN_PATH "." CACHE STRING "Default plugin installation and loading path.")
set(DOCUMENTATION_INSTALL_PATH "doc" CACHE PATH "Path where the documentation is installed.")
else()
@@ -309,6 +311,7 @@ endif()
if(AUDASPACE_STANDALONE)
cmake_dependent_option(SEPARATE_C "Build C Binding as separate library" TRUE "WITH_C" FALSE)
+ cmake_dependent_option(PLUGIN_COREAUDIO "Build CoreAudio Plugin" TRUE "WITH_COREAUDIO;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_FFMPEG "Build FFMPEG Plugin" TRUE "WITH_FFMPEG;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_JACK "Build JACK Plugin" TRUE "WITH_JACK;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_LIBSNDFILE "Build LibSndFile Plugin" TRUE "WITH_LIBSNDFILE;SHARED_LIBRARY" FALSE)
@@ -410,6 +413,44 @@ if(WITH_C)
endif()
endif()
+# CoreAudio
+if(WITH_COREAUDIO)
+ find_library(COREAUDIO_LIBRARY CoreAudio)
+ find_library(AUDIOUNIT_LIBRARY AudioUnit)
+ find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
+ find_path(AUDIOUNIT_INCLUDE_DIR AudioUnit/AudioUnit.h)
+ find_path(AUDIOTOOLBOX_INCLUDE_DIR AudioToolbox/CoreAudioClock.h)
+
+ if(COREAUDIO_LIBRARY AND AUDIOUNIT_LIBRARY AND AUDIOUNIT_INCLUDE_DIR)
+ set(COREAUDIO_LIBRARIES ${COREAUDIO_LIBRARY} ${AUDIOUNIT_LIBRARY} ${AUDIOTOOLBOX_LIBRARY})
+ set(COREAUDIO_INCLUDE_DIRS ${AUDIOUNIT_INCLUDE_DIR} ${AUDIOTOOLBOX_INCLUDE_DIR})
+
+ set(COREAUDIO_SRC
+ plugins/coreaudio/CoreAudioDevice.cpp
+ plugins/coreaudio/CoreAudioSynchronizer.cpp
+ )
+ set(COREAUDIO_HDR
+ plugins/coreaudio/CoreAudioDevice.h
+ plugins/coreaudio/CoreAudioSynchronizer.h
+ )
+
+ if(NOT PLUGIN_COREAUDIO)
+ list(APPEND INCLUDE ${COREAUDIO_INCLUDE_DIRS})
+ list(APPEND LIBRARIES ${COREAUDIO_LIBRARIES})
+ list(APPEND SRC ${COREAUDIO_SRC})
+ list(APPEND HDR ${COREAUDIO_HDR})
+ list(APPEND STATIC_PLUGINS CoreAudioDevice)
+ endif()
+ else()
+ if(WITH_STRICT_DEPENDENCIES)
+ message(ERROR "CoreAudio not found!")
+ else()
+ set(WITH_COREAUDIO FALSE CACHE BOOL "Build With CoreAudio" FORCE)
+ message(WARNING "CoreAudio not found, plugin will not be built.")
+ endif()
+ endif()
+endif()
+
# FFMPEG
if(WITH_FFMPEG)
if(AUDASPACE_STANDALONE)
@@ -820,6 +861,17 @@ endif()
# plugins
+if(WITH_COREAUDIO AND PLUGIN_COREAUDIO)
+ add_definitions(-DCOREAUDIO_PLUGIN)
+ include_directories(${INCLUDE} ${COREAUDIO_INCLUDE_DIRS})
+ add_library(audcoreaudio SHARED ${COREAUDIO_SRC} ${COREAUDIO_HDR} ${HDR})
+ if(WITH_VERSIONED_PLUGINS)
+ set_target_properties(audcoreaudio PROPERTIES SOVERSION ${AUDASPACE_VERSION})
+ endif()
+ target_link_libraries(audcoreaudio audaspace ${COREAUDIO_LIBRARIES})
+ install(TARGETS audcoreaudio DESTINATION ${DEFAULT_PLUGIN_PATH})
+endif()
+
if(WITH_FFMPEG AND PLUGIN_FFMPEG)
add_definitions(-DFFMPEG_PLUGIN)
include_directories(${INCLUDE} ${FFMPEG_INCLUDE_DIRS})
diff --git a/extern/audaspace/blender_config.cmake b/extern/audaspace/blender_config.cmake
index 667788c182b..14d7d593838 100644
--- a/extern/audaspace/blender_config.cmake
+++ b/extern/audaspace/blender_config.cmake
@@ -10,6 +10,7 @@ set(WITH_FFMPEG ${WITH_CODEC_FFMPEG}) # "Build With FFMPEG"
set(WITH_FFTW FALSE) # "Build With FFTW"
set(WITH_LIBSNDFILE ${WITH_CODEC_SNDFILE}) # "Build With LibSndFile"
set(SEPARATE_C FALSE) # "Build C Binding as separate library"
+set(PLUGIN_COREAUDIO FALSE) # "Build CoreAudio Plugin"
set(PLUGIN_FFMPEG FALSE) # "Build FFMPEG Plugin"
set(PLUGIN_JACK FALSE) # "Build JACK Plugin"
set(PLUGIN_LIBSNDFILE FALSE) # "Build LibSndFile Plugin"
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp
new file mode 100644
index 00000000000..113ceccad60
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * Copyright 2009-2021 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "CoreAudioDevice.h"
+#include "devices/DeviceManager.h"
+#include "devices/IDeviceFactory.h"
+#include "Exception.h"
+#include "IReader.h"
+
+AUD_NAMESPACE_BEGIN
+
+OSStatus CoreAudioDevice::CoreAudio_mix(void* data, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time_stamp, UInt32 bus_number, UInt32 number_frames, AudioBufferList* buffer_list)
+{
+ CoreAudioDevice* device = (CoreAudioDevice*)data;
+
+ for(int i = 0; i < buffer_list->mNumberBuffers; i++)
+ {
+ auto& buffer = buffer_list->mBuffers[i];
+
+ device->mix((data_t*)buffer.mData, buffer.mDataByteSize / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
+ }
+
+ return noErr;
+}
+
+void CoreAudioDevice::playing(bool playing)
+{
+ if(m_playback != playing)
+ {
+ if(playing)
+ AudioOutputUnitStart(m_audio_unit);
+ else
+ AudioOutputUnitStop(m_audio_unit);
+ }
+
+ m_playback = playing;
+}
+
+CoreAudioDevice::CoreAudioDevice(DeviceSpecs specs, int buffersize) :
+m_playback(false),
+m_audio_unit(nullptr)
+{
+ AudioComponentDescription component_description = {};
+
+ component_description.componentType = kAudioUnitType_Output;
+ component_description.componentSubType = kAudioUnitSubType_DefaultOutput;
+ component_description.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+ AudioComponent component = AudioComponentFindNext(nullptr, &component_description);
+
+ if(!component)
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+
+ OSStatus status = AudioComponentInstanceNew(component, &m_audio_unit);
+
+ if(status != noErr)
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+
+ AudioStreamBasicDescription stream_basic_description = {};
+
+ if(specs.channels == CHANNELS_INVALID)
+ specs.channels = CHANNELS_STEREO;
+ if(specs.format == FORMAT_INVALID)
+ specs.format = FORMAT_FLOAT32;
+ if(specs.rate == RATE_INVALID)
+ specs.rate = RATE_48000;
+
+ switch(specs.format)
+ {
+ case FORMAT_U8:
+ stream_basic_description.mFormatFlags = 0;
+ stream_basic_description.mBitsPerChannel = 8;
+ break;
+ case FORMAT_S16:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
+ stream_basic_description.mBitsPerChannel = 16;
+ break;
+ case FORMAT_S24:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
+ stream_basic_description.mBitsPerChannel = 24;
+ break;
+ case FORMAT_S32:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
+ stream_basic_description.mBitsPerChannel = 32;
+ break;
+ case FORMAT_FLOAT32:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsFloat;
+ stream_basic_description.mBitsPerChannel = 32;
+ break;
+ case FORMAT_FLOAT64:
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsFloat;
+ stream_basic_description.mBitsPerChannel = 64;
+ break;
+ default:
+ specs.format = FORMAT_FLOAT32;
+ stream_basic_description.mFormatFlags = kLinearPCMFormatFlagIsFloat;
+ stream_basic_description.mBitsPerChannel = 32;
+ break;
+ }
+
+ stream_basic_description.mSampleRate = specs.rate;
+ stream_basic_description.mFormatID = kAudioFormatLinearPCM;
+ stream_basic_description.mFormatFlags |= kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
+ stream_basic_description.mBytesPerPacket = stream_basic_description.mBytesPerFrame = AUD_DEVICE_SAMPLE_SIZE(specs);
+ stream_basic_description.mFramesPerPacket = 1;
+ stream_basic_description.mChannelsPerFrame = specs.channels;
+
+ status = AudioUnitSetProperty(m_audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &stream_basic_description, sizeof(stream_basic_description));
+
+ if(status != noErr)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+ }
+
+ m_specs = specs;
+
+ AURenderCallbackStruct render_callback_struct;
+ render_callback_struct.inputProc = CoreAudioDevice::CoreAudio_mix;
+ render_callback_struct.inputProcRefCon = this;
+
+ status = AudioUnitSetProperty(m_audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &render_callback_struct, sizeof(render_callback_struct));
+
+ if(status != noErr)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+ }
+
+ status = AudioUnitInitialize(m_audio_unit);
+
+ if(status != noErr)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ AUD_THROW(DeviceException, "The audio device couldn't be opened with CoreAudio.");
+ }
+
+ try
+ {
+ m_synchronizer = std::unique_ptr<CoreAudioSynchronizer>(new CoreAudioSynchronizer(m_audio_unit));
+ }
+ catch(Exception&)
+ {
+ AudioComponentInstanceDispose(m_audio_unit);
+ throw;
+ }
+
+ create();
+}
+
+CoreAudioDevice::~CoreAudioDevice()
+{
+ AudioOutputUnitStop(m_audio_unit);
+ AudioUnitUninitialize(m_audio_unit);
+ AudioComponentInstanceDispose(m_audio_unit);
+
+ destroy();
+}
+
+ISynchronizer* CoreAudioDevice::getSynchronizer()
+{
+ return m_synchronizer.get();
+}
+
+class CoreAudioDeviceFactory : public IDeviceFactory
+{
+private:
+ DeviceSpecs m_specs;
+ int m_buffersize;
+
+public:
+ CoreAudioDeviceFactory() :
+ m_buffersize(AUD_DEFAULT_BUFFER_SIZE)
+ {
+ m_specs.format = FORMAT_FLOAT32;
+ m_specs.channels = CHANNELS_STEREO;
+ m_specs.rate = RATE_48000;
+ }
+
+ virtual std::shared_ptr<IDevice> openDevice()
+ {
+ return std::shared_ptr<IDevice>(new CoreAudioDevice(m_specs, m_buffersize));
+ }
+
+ virtual int getPriority()
+ {
+ return 1 << 15;
+ }
+
+ virtual void setSpecs(DeviceSpecs specs)
+ {
+ m_specs = specs;
+ }
+
+ virtual void setBufferSize(int buffersize)
+ {
+ m_buffersize = buffersize;
+ }
+
+ virtual void setName(std::string name)
+ {
+ }
+};
+
+void CoreAudioDevice::registerPlugin()
+{
+ DeviceManager::registerDevice("CoreAudio", std::shared_ptr<IDeviceFactory>(new CoreAudioDeviceFactory));
+}
+
+#ifdef COREAUDIO_PLUGIN
+extern "C" AUD_PLUGIN_API void registerPlugin()
+{
+ CoreAudioDevice::registerPlugin();
+}
+
+extern "C" AUD_PLUGIN_API const char* getName()
+{
+ return "CoreAudio";
+}
+#endif
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioDevice.h b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.h
new file mode 100644
index 00000000000..3770228db6f
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioDevice.h
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright 2009-2021 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef COREAUDIO_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file CoreAudioDevice.h
+ * @ingroup plugin
+ * The CoreAudioDevice class.
+ */
+
+#include "CoreAudioSynchronizer.h"
+#include "devices/SoftwareDevice.h"
+
+#include <memory>
+
+#include <AudioUnit/AudioUnit.h>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This device plays back through CoreAudio, the Apple audio API.
+ */
+class AUD_PLUGIN_API CoreAudioDevice : public SoftwareDevice
+{
+private:
+ /**
+ * Whether there is currently playback.
+ */
+ bool m_playback;
+
+ /**
+ * The CoreAudio AudioUnit.
+ */
+ AudioUnit m_audio_unit;
+
+ /**
+ * The Synchronizer.
+ */
+ std::unique_ptr<CoreAudioSynchronizer> m_synchronizer;
+
+ /**
+ * Mixes the next bytes into the buffer.
+ * \param data The CoreAudio device.
+ * \param flags Unused flags.
+ * \param time_stamp Unused time stamp.
+ * \param bus_number Unused bus number.
+ * \param number_frames Unused number of frames.
+ * \param buffer_list The list of buffers to be filled.
+ */
+ AUD_LOCAL static OSStatus CoreAudio_mix(void* data, AudioUnitRenderActionFlags* flags, const AudioTimeStamp* time_stamp, UInt32 bus_number, UInt32 number_frames, AudioBufferList* buffer_list);
+
+ // delete copy constructor and operator=
+ CoreAudioDevice(const CoreAudioDevice&) = delete;
+ CoreAudioDevice& operator=(const CoreAudioDevice&) = delete;
+
+protected:
+ virtual void playing(bool playing);
+
+public:
+ /**
+ * Opens the CoreAudio audio device for playback.
+ * \param specs The wanted audio specification.
+ * \param buffersize The size of the internal buffer.
+ * \note The specification really used for opening the device may differ.
+ * \exception Exception Thrown if the audio device cannot be opened.
+ */
+ CoreAudioDevice(DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
+
+ /**
+ * Closes the CoreAudio audio device.
+ */
+ virtual ~CoreAudioDevice();
+
+ virtual ISynchronizer* getSynchronizer();
+
+ /**
+ * Registers this plugin.
+ */
+ static void registerPlugin();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp
new file mode 100644
index 00000000000..fcfa7fde9be
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#include "CoreAudioSynchronizer.h"
+
+#include "CoreAudioDevice.h"
+#include "Exception.h"
+
+AUD_NAMESPACE_BEGIN
+
+CoreAudioSynchronizer::CoreAudioSynchronizer(AudioUnit& audio_unit) :
+ m_clock_ref(nullptr),
+ m_playing(false)
+{
+ OSStatus status = CAClockNew(0, &m_clock_ref);
+
+ if(status != noErr)
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+
+ CAClockTimebase timebase = kCAClockTimebase_AudioOutputUnit;
+
+ status = CAClockSetProperty(m_clock_ref, kCAClockProperty_InternalTimebase, sizeof(timebase), &timebase);
+
+ if(status != noErr)
+ {
+ CAClockDispose(m_clock_ref);
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+ }
+
+ status = CAClockSetProperty(m_clock_ref, kCAClockProperty_TimebaseSource, sizeof(audio_unit), &audio_unit);
+
+ if(status != noErr)
+ {
+ CAClockDispose(m_clock_ref);
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+ }
+
+ CAClockSyncMode sync_mode = kCAClockSyncMode_Internal;
+
+ status = CAClockSetProperty(m_clock_ref, kCAClockProperty_SyncMode, sizeof(sync_mode), &sync_mode);
+
+ if(status != noErr)
+ {
+ CAClockDispose(m_clock_ref);
+ AUD_THROW(DeviceException, "Could not create a CoreAudio clock.");
+ }
+}
+
+CoreAudioSynchronizer::~CoreAudioSynchronizer()
+{
+ CAClockDispose(m_clock_ref);
+}
+
+void CoreAudioSynchronizer::seek(std::shared_ptr<IHandle> handle, double time)
+{
+ if(m_playing)
+ CAClockStop(m_clock_ref);
+
+ CAClockTime clock_time;
+ clock_time.format = kCAClockTimeFormat_Seconds;
+ clock_time.time.seconds = time;
+ CAClockSetCurrentTime(m_clock_ref, &clock_time);
+
+ handle->seek(time);
+
+ if(m_playing)
+ CAClockStart(m_clock_ref);
+}
+
+double CoreAudioSynchronizer::getPosition(std::shared_ptr<IHandle> handle)
+{
+ CAClockTime clock_time;
+
+ OSStatus status;
+
+ if(m_playing)
+ status = CAClockGetCurrentTime(m_clock_ref, kCAClockTimeFormat_Seconds, &clock_time);
+ else
+ status = CAClockGetStartTime(m_clock_ref, kCAClockTimeFormat_Seconds, &clock_time);
+
+ if(status != noErr)
+ return 0;
+
+ return clock_time.time.seconds;
+}
+
+void CoreAudioSynchronizer::play()
+{
+ if(m_playing)
+ return;
+
+ m_playing = true;
+ CAClockStart(m_clock_ref);
+}
+
+void CoreAudioSynchronizer::stop()
+{
+ if(!m_playing)
+ return;
+
+ m_playing = false;
+ CAClockStop(m_clock_ref);
+}
+
+void CoreAudioSynchronizer::setSyncCallback(ISynchronizer::syncFunction function, void* data)
+{
+}
+
+int CoreAudioSynchronizer::isPlaying()
+{
+ return m_playing;
+}
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h
new file mode 100644
index 00000000000..4f9d9b28ea5
--- /dev/null
+++ b/extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright 2009-2016 Jörg Müller
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+
+#pragma once
+
+#ifdef COREAUDIO_PLUGIN
+#define AUD_BUILD_PLUGIN
+#endif
+
+/**
+ * @file CoreAudioSynchronizer.h
+ * @ingroup plugin
+ * The CoreAudioSynchronizer class.
+ */
+
+#include "devices/ISynchronizer.h"
+
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/CoreAudioClock.h>
+
+AUD_NAMESPACE_BEGIN
+
+/**
+ * This class is a Synchronizer implementation using a CoreAudio clock.
+ */
+class AUD_PLUGIN_API CoreAudioSynchronizer : public ISynchronizer
+{
+private:
+ /// The CoreAudio clock referene.
+ CAClockRef m_clock_ref;
+
+ /// Whether the clock is currently playing.
+ bool m_playing;
+
+public:
+ /**
+ * Creates a new CoreAudioSynchronizer.
+ * @param device The device that should be synchronized.
+ */
+ CoreAudioSynchronizer(AudioUnit& audio_unit);
+ virtual ~CoreAudioSynchronizer();
+
+ virtual void seek(std::shared_ptr<IHandle> handle, double time);
+ virtual double getPosition(std::shared_ptr<IHandle> handle);
+ virtual void play();
+ virtual void stop();
+ virtual void setSyncCallback(syncFunction function, void* data);
+ virtual int isPlaying();
+};
+
+AUD_NAMESPACE_END
diff --git a/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in b/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in
index d08804bc2e7..3ab24986a0c 100644
--- a/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in
+++ b/extern/audaspace/src/plugin/PluginManagerUnix.cpp.in
@@ -83,7 +83,12 @@ void PluginManager::loadPlugins(const std::string& path)
while(dirent* entry = readdir(dir))
{
const std::string filename = entry->d_name;
+
+#ifdef __APPLE__
+ const std::string end = ".dylib";
+#else
const std::string end = ".so";
+#endif
if(filename.length() >= end.length() && filename.substr(filename.length() - end.length()) == end)
{
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 3069928cea7..4fafa356879 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -298,6 +298,10 @@ if(WITH_OPENAL)
add_definitions(-DWITH_OPENAL)
endif()
+if(WITH_COREAUDIO)
+ add_definitions(-DWITH_COREAUDIO)
+endif()
+
if(WITH_JACK)
add_definitions(-DWITH_JACK)
endif()
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 298491327e0..c7816aed3c1 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -280,6 +280,10 @@ if(WITH_JACK)
add_definitions(-DWITH_JACK)
endif()
+if(WITH_COREAUDIO)
+ add_definitions(-DWITH_COREAUDIO)
+endif()
+
if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index da5f46b9986..f7b71c769d1 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -49,6 +49,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"opensubdiv", NULL},
{"sdl", NULL},
{"sdl_dynload", NULL},
+ {"coreaudio", NULL},
{"jack", NULL},
{"pulseaudio", NULL},
{"wasapi", NULL},
@@ -213,6 +214,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_COREAUDIO
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_JACK
SetObjIncref(Py_True);
#else
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index 562739642dd..5189af3ee85 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -1330,7 +1330,7 @@ static const char arg_handle_audio_set_doc[] =
"\n\t"
"Force sound system to a specific device."
"\n\t"
- "'None' 'SDL' 'OpenAL' 'JACK' 'PulseAudio' 'WASAPI'.";
+ "'None' 'SDL' 'OpenAL' 'CoreAudio' 'JACK' 'PulseAudio' 'WASAPI'.";
static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
{
if (argc < 1) {