forked from bartvdbraak/blender
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
This commit is contained in:
parent
bc57985306
commit
12c08ceee3
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -54,6 +54,9 @@
|
||||
* \ingroup intern undoc
|
||||
* \todo add to doxygen
|
||||
*/
|
||||
/** \defgroup audcoreaudio Audaspace CoreAudio
|
||||
* \ingroup audaspace
|
||||
*/
|
||||
/** \defgroup audfx Audaspace FX
|
||||
* \ingroup audaspace
|
||||
*/
|
||||
|
56
extern/audaspace/CMakeLists.txt
vendored
56
extern/audaspace/CMakeLists.txt
vendored
@ -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})
|
||||
|
1
extern/audaspace/blender_config.cmake
vendored
1
extern/audaspace/blender_config.cmake
vendored
@ -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"
|
||||
|
235
extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp
vendored
Normal file
235
extern/audaspace/plugins/coreaudio/CoreAudioDevice.cpp
vendored
Normal file
@ -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
|
100
extern/audaspace/plugins/coreaudio/CoreAudioDevice.h
vendored
Normal file
100
extern/audaspace/plugins/coreaudio/CoreAudioDevice.h
vendored
Normal file
@ -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
|
127
extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp
vendored
Normal file
127
extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.cpp
vendored
Normal file
@ -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
|
64
extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h
vendored
Normal file
64
extern/audaspace/plugins/coreaudio/CoreAudioSynchronizer.h
vendored
Normal file
@ -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
|
@ -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)
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user