Audaspace: add support for WASAPI on Windows

This adds WASAPI as audio backend on Windows.
WASAPI is the modern standard audio API on
Windows introduced with Windows Vista.

Ref T86590
This commit is contained in:
Joerg Mueller 2021-03-11 19:22:56 +01:00
parent d33339ebf4
commit bc57985306
Notes: blender-bot 2023-02-14 01:35:49 +01:00
Referenced by issue #86590, Audaspace: Use platform native audio APIs
16 changed files with 570 additions and 3 deletions

View File

@ -317,6 +317,11 @@ if(UNIX AND NOT APPLE)
else()
set(WITH_PULSEAUDIO OFF)
endif()
if(WIN32)
option(WITH_WASAPI "Enable Windows Audio Sessions API for audio support on Windows" ON)
else()
set(WITH_WASAPI OFF)
endif()
# Compression
option(WITH_LZO "Enable fast LZO compression (used for pointcache)" ON)
@ -682,6 +687,7 @@ endif()
set_and_warn_dependency(WITH_AUDASPACE WITH_OPENAL 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)
if(NOT WITH_SDL AND WITH_GHOST_SDL)
message(FATAL_ERROR "WITH_GHOST_SDL requires WITH_SDL")
@ -1946,6 +1952,7 @@ if(FIRST_RUN)
info_cfg_option(WITH_SDL_DYNLOAD)
info_cfg_option(WITH_PULSEAUDIO)
info_cfg_option(WITH_PULSEAUDIO_DYNLOAD)
info_cfg_option(WITH_WASAPI)
info_cfg_text("Compression:")
info_cfg_option(WITH_LZMA)

View File

@ -62,6 +62,9 @@ set(WITH_MEM_JEMALLOC ON CACHE BOOL "" FORCE)
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
if(WIN32)
set(WITH_WASAPI ON CACHE BOOL "" FORCE)
endif()
if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)

View File

@ -14,6 +14,7 @@ set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
set(WITH_WASAPI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)

View File

@ -44,6 +44,7 @@ set(WITH_MOD_FLUID OFF CACHE BOOL "" FORCE)
set(WITH_MOD_OCEANSIM OFF CACHE BOOL "" FORCE)
set(WITH_MOD_REMESH OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
set(WITH_WASAPI OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLLADA OFF CACHE BOOL "" FORCE)
set(WITH_OPENCOLORIO OFF CACHE BOOL "" FORCE)
set(WITH_OPENIMAGEDENOISE OFF CACHE BOOL "" FORCE)

View File

@ -66,6 +66,9 @@ set(WITH_CYCLES_DEVICE_OPTIX ON CACHE BOOL "" FORCE)
if(NOT WIN32)
set(WITH_JACK ON CACHE BOOL "" FORCE)
endif()
if(WIN32)
set(WITH_WASAPI ON CACHE BOOL "" FORCE)
endif()
if(UNIX AND NOT APPLE)
set(WITH_DOC_MANPAGE ON CACHE BOOL "" FORCE)
set(WITH_GHOST_XDND ON CACHE BOOL "" FORCE)

View File

@ -19,6 +19,7 @@ set(WITH_JACK OFF CACHE BOOL "" FORCE)
set(WITH_PULSEAUDIO OFF CACHE BOOL "" FORCE)
set(WITH_SDL OFF CACHE BOOL "" FORCE)
set(WITH_OPENAL OFF CACHE BOOL "" FORCE)
set(WITH_WASAPI OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_FFMPEG OFF CACHE BOOL "" FORCE)
set(WITH_CODEC_SNDFILE OFF CACHE BOOL "" FORCE)

View File

@ -63,6 +63,9 @@
/** \defgroup audpulseaudio Audaspace PulseAudio
* \ingroup audaspace
*/
/** \defgroup audwasapi Audaspace WASAPI
* \ingroup audaspace
*/
/** \defgroup audpython Audaspace Python
* \ingroup audaspace
*/

View File

@ -288,6 +288,9 @@ if(AUDASPACE_STANDALONE)
if(NOT WIN32 AND NOT APPLE)
option(WITH_PULSEAUDIO "Build With PulseAudio" TRUE)
endif()
if(WIN32)
option(WITH_WASAPI "Build With WASAPI" TRUE)
endif()
if(WITH_STRICT_DEPENDENCIES)
set(PACKAGE_OPTION REQUIRED)
@ -312,6 +315,7 @@ if(AUDASPACE_STANDALONE)
cmake_dependent_option(PLUGIN_OPENAL "Build OpenAL Plugin" TRUE "WITH_OPENAL;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_PULSEAUDIO "Build PulseAudio Plugin" TRUE "WITH_PULSEAUDIO;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_SDL "Build SDL Plugin" TRUE "WITH_SDL;SHARED_LIBRARY" FALSE)
cmake_dependent_option(PLUGIN_WASAPI "Build WASAPI Plugin" TRUE "WITH_WASAPI;SHARED_LIBRARY" FALSE)
cmake_dependent_option(WITH_PYTHON_MODULE "Build Python Module" TRUE "WITH_PYTHON" FALSE)
cmake_dependent_option(USE_SDL2 "Use SDL2 instead of 1 if available" TRUE "WITH_SDL" FALSE)
cmake_dependent_option(DYNLOAD_JACK "Dynamically load JACK" FALSE "WITH_JACK" FALSE)
@ -714,6 +718,23 @@ if(WITH_SDL)
endif()
endif()
# WASAPI
if(WITH_WASAPI)
set(WASAPI_SRC
plugins/wasapi/WASAPIDevice.cpp
)
set(WASAPI_HDR
plugins/wasapi/WASAPIDevice.h
)
if(NOT PLUGIN_WASAPI)
list(APPEND LIBRARIES ksuser)
list(APPEND SRC ${WASAPI_SRC})
list(APPEND HDR ${WASAPI_HDR})
list(APPEND STATIC_PLUGINS WASAPIDevice)
endif()
endif()
# library configuration
if(SHARED_LIBRARY)
@ -861,6 +882,17 @@ if(WITH_SDL AND PLUGIN_SDL)
install(TARGETS audsdl DESTINATION ${DEFAULT_PLUGIN_PATH})
endif()
if(WITH_WASAPI AND PLUGIN_WASAPI)
add_definitions(-DWASAPI_PLUGIN)
include_directories(${INCLUDE})
add_library(audwasapi SHARED ${WASAPI_SRC} ${WASAPI_HDR} ${HDR})
if(WITH_VERSIONED_PLUGINS)
set_target_properties(audwasapi PROPERTIES SOVERSION ${AUDASPACE_VERSION})
endif()
target_link_libraries(audwasapi audaspace ksuser)
install(TARGETS audwasapi DESTINATION ${DEFAULT_PLUGIN_PATH})
endif()
# dlls
if(WIN32)

View File

@ -16,6 +16,7 @@ set(PLUGIN_LIBSNDFILE FALSE) # "Build LibSndFile Plugin"
set(PLUGIN_OPENAL FALSE) # "Build OpenAL Plugin"
set(PLUGIN_PULSEAUDIO FALSE) # "Build PulseAudio Plugin"
set(PLUGIN_SDL FALSE) # "Build SDL Plugin"
set(PLUGIN_WASAPI FALSE) # "Build WASAPI Plugin"
set(WITH_PYTHON_MODULE FALSE) # "Build Python Module"
set(DYNLOAD_JACK ${WITH_JACK_DYNLOAD}) # "Dynamically load JACK"
set(DYNLOAD_PULSEAUDIO ${WITH_PULSEAUDIO_DYNLOAD}) # "Dynamically load PulseAudio"

View File

@ -0,0 +1,401 @@
/*******************************************************************************
* 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 "WASAPIDevice.h"
#include "devices/DeviceManager.h"
#include "devices/IDeviceFactory.h"
#include "Exception.h"
#include "IReader.h"
AUD_NAMESPACE_BEGIN
template <class T> void SafeRelease(T **ppT)
{
if(*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
void WASAPIDevice::start()
{
lock();
if(!m_playing)
{
if(m_thread.joinable())
m_thread.join();
m_playing = true;
m_thread = std::thread(&WASAPIDevice::updateStream, this);
}
unlock();
}
void WASAPIDevice::updateStream()
{
UINT32 buffer_size;
data_t* buffer;
if(FAILED(m_audio_client->GetBufferSize(&buffer_size)))
return;
IAudioRenderClient* render_client = nullptr;
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
if(FAILED(m_audio_client->GetService(IID_IAudioRenderClient, reinterpret_cast<void**>(&render_client))))
return;
UINT32 padding;
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
SafeRelease(&render_client);
return;
}
UINT32 length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
SafeRelease(&render_client);
return;
}
lock();
mix((data_t*)buffer, length);
unlock();
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
SafeRelease(&render_client);
return;
}
m_audio_client->Start();
auto sleepDuration = std::chrono::milliseconds(buffer_size * 1000 / int(m_specs.rate) / 2);
for(;;)
{
if(FAILED(m_audio_client->GetCurrentPadding(&padding)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
return;
}
length = buffer_size - padding;
if(FAILED(render_client->GetBuffer(length, &buffer)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
return;
}
lock();
mix((data_t*)buffer, length);
unlock();
if(FAILED(render_client->ReleaseBuffer(length, 0)))
{
m_audio_client->Stop();
SafeRelease(&render_client);
return;
}
// stop thread
if(!m_playing)
{
m_audio_client->Stop();
SafeRelease(&render_client);
return;
}
std::this_thread::sleep_for(sleepDuration);
}
}
void WASAPIDevice::playing(bool playing)
{
if(!m_playing && playing)
start();
else
m_playing = playing;
}
WASAPIDevice::WASAPIDevice(DeviceSpecs specs, int buffersize) :
m_playing(false),
m_imm_device_enumerator(nullptr),
m_imm_device(nullptr),
m_audio_client(nullptr),
m_wave_format_extensible({})
{
// initialize COM if it hasn't happened yet
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
WAVEFORMATEXTENSIBLE wave_format_extensible_closest_match;
WAVEFORMATEXTENSIBLE* closest_match_pointer = &wave_format_extensible_closest_match;
HRESULT result;
REFERENCE_TIME minimum_time = 0;
REFERENCE_TIME buffer_duration;
if(FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, reinterpret_cast<void**>(&m_imm_device_enumerator))))
goto error;
if(FAILED(m_imm_device_enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &m_imm_device)))
goto error;
if(FAILED(m_imm_device->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&m_audio_client))))
goto error;
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:
case FORMAT_S16:
case FORMAT_S24:
case FORMAT_S32:
m_wave_format_extensible.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
break;
case FORMAT_FLOAT32:
m_wave_format_extensible.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
break;
default:
m_wave_format_extensible.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
specs.format = FORMAT_FLOAT32;
break;
}
switch(specs.channels)
{
case CHANNELS_MONO:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_CENTER;
break;
case CHANNELS_STEREO:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
break;
case CHANNELS_STEREO_LFE:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY;
break;
case CHANNELS_SURROUND4:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case CHANNELS_SURROUND5:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case CHANNELS_SURROUND51:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT;
break;
case CHANNELS_SURROUND61:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
break;
case CHANNELS_SURROUND71:
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT;
break;
default:
specs.channels = CHANNELS_STEREO;
m_wave_format_extensible.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
break;
}
m_wave_format_extensible.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
m_wave_format_extensible.Format.nChannels = specs.channels;
m_wave_format_extensible.Format.nSamplesPerSec = specs.rate;
m_wave_format_extensible.Format.nAvgBytesPerSec = specs.rate * AUD_DEVICE_SAMPLE_SIZE(specs);
m_wave_format_extensible.Format.nBlockAlign = AUD_DEVICE_SAMPLE_SIZE(specs);
m_wave_format_extensible.Format.wBitsPerSample = AUD_FORMAT_SIZE(specs.format) * 8;
m_wave_format_extensible.Format.cbSize = 22;
m_wave_format_extensible.Samples.wValidBitsPerSample = m_wave_format_extensible.Format.wBitsPerSample;
result = m_audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, reinterpret_cast<const WAVEFORMATEX*>(&m_wave_format_extensible), reinterpret_cast<WAVEFORMATEX**>(&closest_match_pointer));
if(result == S_FALSE)
{
if(closest_match_pointer->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
goto error;
specs.channels = Channels(closest_match_pointer->Format.nChannels);
specs.rate = closest_match_pointer->Format.nSamplesPerSec;
if(closest_match_pointer->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
{
if(closest_match_pointer->Format.wBitsPerSample == 32)
specs.format = FORMAT_FLOAT32;
else if(closest_match_pointer->Format.wBitsPerSample == 64)
specs.format = FORMAT_FLOAT64;
else
goto error;
}
else if(closest_match_pointer->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
{
switch(closest_match_pointer->Format.wBitsPerSample)
{
case 8:
specs.format = FORMAT_U8;
break;
case 16:
specs.format = FORMAT_S16;
break;
case 24:
specs.format = FORMAT_S24;
break;
case 32:
specs.format = FORMAT_S32;
break;
default:
goto error;
break;
}
}
else
goto error;
m_wave_format_extensible = *closest_match_pointer;
if(closest_match_pointer != &wave_format_extensible_closest_match)
{
CoTaskMemFree(closest_match_pointer);
closest_match_pointer = &wave_format_extensible_closest_match;
}
}
else if(FAILED(result))
goto error;
if(FAILED(m_audio_client->GetDevicePeriod(nullptr, &minimum_time)))
goto error;
buffer_duration = REFERENCE_TIME(buffersize) * REFERENCE_TIME(10000000) / REFERENCE_TIME(specs.rate);
if(minimum_time > buffer_duration)
buffer_duration = minimum_time;
m_specs = specs;
if(FAILED(m_audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, buffer_duration, 0, reinterpret_cast<WAVEFORMATEX*>(&m_wave_format_extensible), nullptr)))
goto error;
create();
return;
error:
if(closest_match_pointer != &wave_format_extensible_closest_match)
CoTaskMemFree(closest_match_pointer);
SafeRelease(&m_imm_device);
SafeRelease(&m_imm_device_enumerator);
SafeRelease(&m_audio_client);
AUD_THROW(DeviceException, "The audio device couldn't be opened with WASAPI.");
}
WASAPIDevice::~WASAPIDevice()
{
lock();
stopAll();
unlock();
if(m_thread.joinable())
m_thread.join();
SafeRelease(&m_audio_client);
SafeRelease(&m_imm_device);
SafeRelease(&m_imm_device_enumerator);
destroy();
}
class WASAPIDeviceFactory : public IDeviceFactory
{
private:
DeviceSpecs m_specs;
int m_buffersize;
public:
WASAPIDeviceFactory() :
m_buffersize(AUD_DEFAULT_BUFFER_SIZE)
{
m_specs.format = FORMAT_S16;
m_specs.channels = CHANNELS_STEREO;
m_specs.rate = RATE_48000;
}
virtual std::shared_ptr<IDevice> openDevice()
{
return std::shared_ptr<IDevice>(new WASAPIDevice(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 WASAPIDevice::registerPlugin()
{
DeviceManager::registerDevice("WASAPI", std::shared_ptr<IDeviceFactory>(new WASAPIDeviceFactory));
}
#ifdef WASAPI_PLUGIN
extern "C" AUD_PLUGIN_API void registerPlugin()
{
WASAPIDevice::registerPlugin();
}
extern "C" AUD_PLUGIN_API const char* getName()
{
return "WASAPI";
}
#endif
AUD_NAMESPACE_END

View File

@ -0,0 +1,99 @@
/*******************************************************************************
* 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 WASAPI_PLUGIN
#define AUD_BUILD_PLUGIN
#endif
/**
* @file WASAPIDevice.h
* @ingroup plugin
* The WASAPIDevice class.
*/
#include "devices/SoftwareDevice.h"
#include <thread>
#include <windows.h>
#include <audioclient.h>
#include <mmdeviceapi.h>
#include <mmreg.h>
AUD_NAMESPACE_BEGIN
/**
* This device plays back through WASAPI, the Windows audio API.
*/
class AUD_PLUGIN_API WASAPIDevice : public SoftwareDevice
{
private:
/**
* Whether there is currently playback.
*/
bool m_playing;
IMMDeviceEnumerator* m_imm_device_enumerator;
IMMDevice* m_imm_device;
IAudioClient* m_audio_client;
WAVEFORMATEXTENSIBLE m_wave_format_extensible;
/**
* The streaming thread.
*/
std::thread m_thread;
/**
* Starts the streaming thread.
*/
AUD_LOCAL void start();
/**
* Streaming thread main function.
*/
AUD_LOCAL void updateStream();
// delete copy constructor and operator=
WASAPIDevice(const WASAPIDevice&) = delete;
WASAPIDevice& operator=(const WASAPIDevice&) = delete;
protected:
virtual void playing(bool playing);
public:
/**
* Opens the WASAPI 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.
*/
WASAPIDevice(DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
/**
* Closes the WASAPI audio device.
*/
virtual ~WASAPIDevice();
/**
* Registers this plugin.
*/
static void registerPlugin();
};
AUD_NAMESPACE_END

View File

@ -27,9 +27,9 @@ void* PluginManager::openLibrary(const std::string& path)
return reinterpret_cast<void*>(LoadLibrary(path.c_str()));
}
void *PluginManager::lookupLibrary(void *handle, const std::string &name)
void* PluginManager::lookupLibrary(void *handle, const std::string &name)
{
return GetProcAddress(reinterpret_cast<HMODULE>(handle), name.c_str());
return reinterpret_cast<void*>(GetProcAddress(reinterpret_cast<HMODULE>(handle), name.c_str()));
}
void PluginManager::closeLibrary(void *handle)

View File

@ -306,6 +306,10 @@ if(WITH_PULSEAUDIO)
add_definitions(-DWITH_PULSEAUDIO)
endif()
if(WITH_WASAPI)
add_definitions(-DWITH_WASAPI)
endif()
if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()

View File

@ -288,6 +288,10 @@ if(WITH_PULSEAUDIO)
add_definitions(-DWITH_PULSEAUDIO)
endif()
if(WITH_WASAPI)
add_definitions(-DWITH_WASAPI)
endif()
if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()

View File

@ -51,6 +51,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{"sdl_dynload", NULL},
{"jack", NULL},
{"pulseaudio", NULL},
{"wasapi", NULL},
{"libmv", NULL},
{"mod_oceansim", NULL},
{"mod_remesh", NULL},
@ -224,6 +225,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
#ifdef WITH_WASAPI
SetObjIncref(Py_True);
#else
SetObjIncref(Py_False);
#endif
#ifdef WITH_LIBMV
SetObjIncref(Py_True);
#else

View File

@ -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'.";
"'None' 'SDL' 'OpenAL' 'JACK' 'PulseAudio' 'WASAPI'.";
static int arg_handle_audio_set(int argc, const char **argv, void *UNUSED(data))
{
if (argc < 1) {