| diff --git a/Alc/ALc.c b/Alc/ALc.c |
| --- a/Alc/ALc.c |
| +++ b/Alc/ALc.c |
| @@ -61,6 +61,9 @@ struct BackendInfo { |
| |
| #define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } |
| static struct BackendInfo BackendList[] = { |
| +#ifdef HAVE_PPAPI |
| + { "ppapi", NULL, alc_ppapi_init, alc_ppapi_deinit, alc_ppapi_probe, EmptyFuncs }, |
| +#endif |
| #ifdef HAVE_PULSEAUDIO |
| { "pulse", ALCpulseBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, |
| #endif |
| diff --git a/Alc/backends/ppapi.c b/Alc/backends/ppapi.c |
| new file mode 100644 |
| --- /dev/null |
| +++ b/Alc/backends/ppapi.c |
| @@ -0,0 +1,458 @@ |
| +/** |
| + * OpenAL cross platform audio library |
| + * Copyright (C) 2012 |
| + * This library is free software; you can redistribute it and/or |
| + * modify it under the terms of the GNU Library General Public |
| + * License as published by the Free Software Foundation; either |
| + * version 2 of the License, or (at your option) any later version. |
| + * |
| + * This library is distributed in the hope that it will be useful, |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| + * Library General Public License for more details. |
| + * |
| + * You should have received a copy of the GNU Library General Public |
| + * License along with this library; if not, write to the |
| + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| + * Boston, MA 02111-1307, USA. |
| + * Or go to http://www.gnu.org/copyleft/lgpl.html |
| + */ |
| + |
| +#include "config.h" |
| + |
| +#include "alMain.h" |
| +#include "alu.h" |
| +#include "AL/al.h" |
| +#include "AL/alc.h" |
| +#include "threads.h" |
| + |
| +#include <ppapi/c/pp_completion_callback.h> |
| +#include <ppapi/c/pp_instance.h> |
| +#include <ppapi/c/ppb.h> |
| +#include <ppapi/c/ppb_audio.h> |
| +#include <ppapi/c/ppb_audio_config.h> |
| +#include <ppapi/c/ppb_core.h> |
| +#include <stdlib.h> |
| + |
| +/* |
| + * The output buffer will be this multiple of the OpenAL device update size. |
| + * This needs to be at least 2 or we can't buffer output properly. |
| + */ |
| +const ALuint kBufferPadMult = 4; |
| + |
| +/* |
| + * How many samples for each frame will be buffered to Pepper. |
| + * Keep this low for low latency, but not too low or we will be CPU bound. |
| + */ |
| +const ALuint kRequestedFrameCount = 1024; |
| + |
| +/* |
| + * 4 is 2-channels, 2-bytes per sample. |
| + */ |
| +const ALuint kFrameSizeInBytes = 4; |
| + |
| +typedef struct { |
| + /* |
| + * Simple circular buffer (single producer/consumer) to buffer data output |
| + * from OpenAL before it's handed off to PPAPI. |
| + */ |
| + ALvoid *buffer; |
| + ALuint size; |
| + |
| + struct PPB_AudioConfig_1_1* audio_config; |
| + struct PPB_Audio_1_1* audio; |
| + struct PPB_Core_1_0* core; |
| + |
| + PP_Resource audio_config_res; |
| + PP_Resource audio_res; |
| + ALuint sample_frame_count; |
| + |
| + volatile ALuint read_ptr; |
| + volatile ALuint write_ptr; |
| + |
| + ALCdevice *device; |
| + |
| + volatile int killNow; |
| + althrd_t thread; |
| + volatile ALint main_thread_init_status; |
| + ALuint buffer_ready; |
| +} ppapi_data; |
| + |
| +static PP_Instance gInstance; |
| +static PPB_GetInterface gGetInterface; |
| + |
| +AL_API void AL_APIENTRY alSetPpapiInfo(PP_Instance instance, PPB_GetInterface get_interface) |
| +{ |
| + TRACE("alSetPpapiInfo\n"); |
| + gInstance = instance; |
| + gGetInterface = get_interface; |
| +} |
| + |
| +/* This is the callback from PPAPI to fill in the audio buffer. */ |
| +void PPAPI_Audio_Callback(void *sample_buffer, |
| + uint32_t buffer_size_in_bytes, |
| + PP_TimeDelta UNUSED(latency), |
| + void* user_data) |
| +{ |
| + ppapi_data* data = (ppapi_data*)user_data; |
| + if(!data->buffer_ready) return; |
| + |
| + ALuint write_proxy = data->write_ptr; |
| + if(data->read_ptr > data->write_ptr) |
| + write_proxy = data->write_ptr + data->size; |
| + |
| + ALuint available_bytes = write_proxy - data->read_ptr; |
| + if(available_bytes < buffer_size_in_bytes) |
| + { |
| + WARN("buffer underrun (buffer size=%d) (only buffering %d)\n", |
| + buffer_size_in_bytes, available_bytes); |
| + /* Zero the part of the buffer that we cannot fill */ |
| + memset(sample_buffer + available_bytes, |
| + 0, |
| + buffer_size_in_bytes - available_bytes); |
| + buffer_size_in_bytes = available_bytes; |
| + } |
| + |
| + if(data->read_ptr + buffer_size_in_bytes > data->size) |
| + { |
| + /* This read straddles the buffer boundary, split it up. */ |
| + memcpy(sample_buffer, |
| + data->buffer + data->read_ptr, |
| + data->size - data->read_ptr); |
| + memcpy(sample_buffer + (data->size - data->read_ptr), |
| + data->buffer, |
| + buffer_size_in_bytes - (data->size - data->read_ptr)); |
| + } |
| + else |
| + { |
| + memcpy(sample_buffer, |
| + data->buffer + data->read_ptr, |
| + buffer_size_in_bytes); |
| + } |
| + |
| + data->read_ptr += buffer_size_in_bytes; |
| + if(data->read_ptr >= data->size) |
| + data->read_ptr -= data->size; |
| +} |
| + |
| +static const ALCchar ppapiDevice[] = "PPAPI Output"; |
| + |
| +static int ppapi_thread(ALvoid *ptr) |
| +{ |
| + ALCdevice *Device = (ALCdevice*)ptr; |
| + ppapi_data *data = (ppapi_data*)Device->ExtraData; |
| + |
| + ALuint UpdateSizeInBytes = Device->UpdateSize * kFrameSizeInBytes; |
| + ALuint SampleFrameInBytes = data->sample_frame_count * kFrameSizeInBytes; |
| + |
| + /* |
| + * Start to buffer when less than this many bytes are buffered. Keep this |
| + * small for low latency but large enough so we don't starve Pepper. |
| + * |
| + * SampleFrameInBytes is the size of the buffer that PPAPI asks for each |
| + * callback. We want to keep twice this amount in the buffer at any given |
| + * time. |
| + */ |
| + const ALuint MinBufferSizeInBytes = maxu(SampleFrameInBytes*2, |
| + UpdateSizeInBytes); |
| + |
| + while(!data->killNow && Device->Connected) |
| + { |
| + ALuint write_proxy = data->write_ptr; |
| + if(data->read_ptr > data->write_ptr) |
| + write_proxy = data->write_ptr + data->size; |
| + |
| + if(data->read_ptr + MinBufferSizeInBytes >= write_proxy) |
| + { |
| + aluMixData(Device, |
| + data->buffer + data->write_ptr, |
| + Device->UpdateSize); |
| + if(data->write_ptr + UpdateSizeInBytes > data->size) |
| + { |
| + /* |
| + * Spilled over the edge, copy the last bits to the beginning |
| + * of the buffer. |
| + */ |
| + memcpy(data->buffer, |
| + data->buffer + data->size, |
| + UpdateSizeInBytes - (data->size - data->write_ptr)); |
| + } |
| + |
| + data->write_ptr += UpdateSizeInBytes; |
| + if(data->write_ptr >= data->size) |
| + data->write_ptr -= data->size; |
| + } |
| + /* Small 1 ms sleep so we don't use too much CPU time. */ |
| + al_nssleep(0, 1000000); |
| + } |
| + |
| + return 0; |
| +} |
| + |
| +/* This needs to be called on the main PPAPI thread. */ |
| +static void ppapi_open_playback_main_thread(void* user_data, int32_t result) |
| +{ |
| + ppapi_data *data = (ppapi_data*)user_data; |
| + (void)result; |
| + |
| + PP_AudioSampleRate rate = PP_AUDIOSAMPLERATE_44100; |
| + if(data->device->Frequency == 48000) |
| + rate = PP_AUDIOSAMPLERATE_48000; |
| + |
| + data->sample_frame_count = |
| + data->audio_config->RecommendSampleFrameCount( |
| +#ifdef PPB_AUDIO_CONFIG_INTERFACE_1_1 |
| + gInstance, |
| +#endif |
| + rate, |
| + kRequestedFrameCount); |
| + |
| + data->audio_config_res = |
| + data->audio_config->CreateStereo16Bit(gInstance, |
| + rate, |
| + data->sample_frame_count); |
| + |
| + if(data->audio_config->IsAudioConfig(data->audio_config_res) == PP_FALSE) |
| + { |
| + ERR("PPAPI initialization: audio config creation failed."); |
| + data->main_thread_init_status = -1; |
| + return; |
| + } |
| + |
| + data->audio_res = data->audio->Create(gInstance, |
| + data->audio_config_res, |
| + PPAPI_Audio_Callback, |
| + (void*)data); |
| + |
| + if(PP_FALSE == data->audio->IsAudio(data->audio_res)) |
| + { |
| + ERR("PPAPI initialization: audio resource creation failed."); |
| + data->main_thread_init_status = -1; |
| + return; |
| + } |
| + |
| + if(PP_FALSE == data->audio->StartPlayback(data->audio_res)) |
| + { |
| + ERR("PPAPI initialization: start playback failed."); |
| + data->main_thread_init_status = -1; |
| + return; |
| + } |
| + |
| + data->main_thread_init_status = 1; |
| +} |
| + |
| +static ALCenum ppapi_open_playback(ALCdevice *device, |
| + const ALCchar *deviceName) |
| +{ |
| + TRACE("ppapi_open_playback\n"); |
| + ppapi_data *data; |
| + |
| + if(!deviceName) |
| + deviceName = ppapiDevice; |
| + else if(strcmp(deviceName, ppapiDevice) != 0) |
| + return ALC_INVALID_VALUE; |
| + |
| + int channels = ChannelsFromDevFmt(device->FmtChans); |
| + int bytes = BytesFromDevFmt(device->FmtType); |
| + |
| + if(channels != 2) |
| + { |
| + WARN("PPAPI only supports 2 channel output " |
| + "(%d channels requested)\n", channels); |
| + return ALC_INVALID_VALUE; |
| + } |
| + if(bytes != 2) |
| + { |
| + WARN("PPAPI only supports 16-bit output " |
| + "(%d bytes-per-channel requested, format=%#x)\n", bytes, device->FmtType); |
| + return ALC_INVALID_VALUE; |
| + } |
| + if(device->Frequency != 44100 && device->Frequency != 44800) |
| + { |
| + WARN("PPAPI only supports 44100 and 44800 sample frequencies " |
| + "(%d requested)\n", device->Frequency); |
| + return ALC_INVALID_VALUE; |
| + } |
| + |
| + data = (ppapi_data*)calloc(1, sizeof(*data)); |
| + |
| + device->ExtraData = data; |
| + data->device = device; |
| + |
| + data->audio_config = (struct PPB_AudioConfig_1_1 *)gGetInterface( |
| + PPB_AUDIO_CONFIG_INTERFACE_1_1); |
| + if(!data->audio_config) |
| + { |
| + free(data); |
| + return ALC_INVALID_VALUE; |
| + } |
| + |
| + data->audio = (struct PPB_Audio_1_1*)gGetInterface(PPB_AUDIO_INTERFACE_1_1); |
| + if(!data->audio) |
| + { |
| + free(data); |
| + return ALC_INVALID_VALUE; |
| + } |
| + |
| + data->core = (struct PPB_Core_1_0*)gGetInterface(PPB_CORE_INTERFACE_1_0); |
| + if(!data->core) |
| + { |
| + free(data); |
| + return ALC_INVALID_VALUE; |
| + } |
| + |
| + al_string_copy_cstr(&device->DeviceName, deviceName); |
| + |
| + return ALC_NO_ERROR; |
| +} |
| + |
| + |
| +/* This needs to be called on the main PPAPI thread. */ |
| +static void ppapi_close_playback_main_thread(void* user_data, |
| + int32_t UNUSED(result)) |
| +{ |
| + ppapi_data *data = (ppapi_data*)user_data; |
| + |
| + data->audio->StopPlayback(data->audio_res); |
| + |
| + data->core->ReleaseResource(data->audio_res); |
| + data->core->ReleaseResource(data->audio_config_res); |
| + |
| + if(data->buffer) |
| + free(data->buffer); |
| + free(data); |
| +} |
| + |
| +static void ppapi_close_playback(ALCdevice *device) |
| +{ |
| + ppapi_data *data = (ppapi_data*)device->ExtraData; |
| + |
| + if(data->core->IsMainThread()) |
| + { |
| + ppapi_close_playback_main_thread(data, 0); |
| + } |
| + else |
| + { |
| + struct PP_CompletionCallback cb = |
| + PP_MakeCompletionCallback(ppapi_close_playback_main_thread, data); |
| + data->core->CallOnMainThread(0, cb, 0); |
| + } |
| + |
| + device->ExtraData = NULL; |
| +} |
| + |
| +static ALCboolean ppapi_reset_playback(ALCdevice *device) |
| +{ |
| + ppapi_data *data = (ppapi_data*)device->ExtraData; |
| + |
| + ALuint UpdateSizeInBytes = device->UpdateSize * kFrameSizeInBytes; |
| + ALuint SampleFrameInBytes = data->sample_frame_count * kFrameSizeInBytes; |
| + /* kBufferPadMult is added to protect against buffer underruns. */ |
| + data->size = maxu(UpdateSizeInBytes, SampleFrameInBytes) * kBufferPadMult; |
| + |
| + /* Extra UpdateSize added so we can read off the end of the buffer in one |
| + * shot from aluMixData, but treat the buffer like it's of size data->size. |
| + */ |
| + data->buffer = calloc(1, data->size + UpdateSizeInBytes); |
| + if(!data->buffer) |
| + { |
| + ERR("buffer malloc failed\n"); |
| + return ALC_FALSE; |
| + } |
| + SetDefaultWFXChannelOrder(device); |
| + |
| + data->read_ptr = 0; |
| + data->write_ptr = 0; |
| + data->buffer_ready = 1; |
| + return ALC_TRUE; |
| +} |
| + |
| +static ALCboolean ppapi_start_playback(ALCdevice *device) |
| +{ |
| + TRACE("ppapi_start_playback\n"); |
| + ppapi_data *data = (ppapi_data*)device->ExtraData; |
| + |
| + if(althrd_create(&data->thread, ppapi_thread, device) != althrd_success) |
| + { |
| + free(data->buffer); |
| + data->buffer = NULL; |
| + return ALC_FALSE; |
| + } |
| + |
| + if(data->core->IsMainThread()) |
| + { |
| + ppapi_open_playback_main_thread(data, 0); |
| + } |
| + else |
| + { |
| + struct PP_CompletionCallback cb = |
| + PP_MakeCompletionCallback(ppapi_open_playback_main_thread, data); |
| + data->core->CallOnMainThread(0, cb, 0); |
| + |
| + while(data->main_thread_init_status == 0) |
| + al_nssleep(0, 1000000); |
| + } |
| + |
| + if(data->main_thread_init_status < 0) { |
| + free(data); |
| + return ALC_FALSE; |
| + } |
| + |
| + return ALC_TRUE; |
| +} |
| + |
| +static void ppapi_stop_playback(ALCdevice *device) |
| +{ |
| + ppapi_data *data = (ppapi_data*)device->ExtraData; |
| + |
| + if(data->killNow) |
| + return; |
| + |
| + int res; |
| + data->killNow = 1; |
| + althrd_join(data->thread, &res); |
| + data->killNow = 0; |
| + |
| + data->buffer_ready = 0; |
| + free(data->buffer); |
| + data->buffer = NULL; |
| +} |
| + |
| + |
| +BackendFuncs ppapi_funcs = { |
| + ppapi_open_playback, |
| + ppapi_close_playback, |
| + ppapi_reset_playback, |
| + ppapi_start_playback, |
| + ppapi_stop_playback, |
| + |
| + NULL, |
| + NULL, |
| + NULL, |
| + NULL, |
| + NULL, |
| + NULL, |
| + |
| + ALCdevice_GetLatencyDefault |
| +}; |
| + |
| +ALCboolean alc_ppapi_init(BackendFuncs *func_list) |
| +{ |
| + TRACE("alc_ppapi_init\n"); |
| + *func_list = ppapi_funcs; |
| + return ALC_TRUE; |
| +} |
| + |
| +void alc_ppapi_deinit(void) |
| +{ |
| + TRACE("alc_ppapi_deinit\n"); |
| +} |
| + |
| +void alc_ppapi_probe(enum DevProbe type) |
| +{ |
| + TRACE("alc_ppapi_probe\n"); |
| + if(type == CAPTURE_DEVICE_PROBE) |
| + AppendCaptureDeviceList(ppapiDevice); |
| + else if(type == ALL_DEVICE_PROBE) |
| + AppendAllDevicesList(ppapiDevice); |
| +} |
| diff --git a/Alc/mixer_neon.c b/Alc/mixer_neon.c |
| --- a/Alc/mixer_neon.c |
| +++ b/Alc/mixer_neon.c |
| @@ -75,7 +75,7 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], |
| #undef SUFFIX |
| |
| |
| -void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], |
| +void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], |
| MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) |
| { |
| ALfloat gain, step; |
| diff --git a/CMakeLists.txt b/CMakeLists.txt |
| --- a/CMakeLists.txt |
| +++ b/CMakeLists.txt |
| @@ -611,6 +611,7 @@ SET(HAVE_MMDEVAPI 0) |
| SET(HAVE_WINMM 0) |
| SET(HAVE_PORTAUDIO 0) |
| SET(HAVE_PULSEAUDIO 0) |
| +SET(HAVE_PPAPI 0) |
| SET(HAVE_COREAUDIO 0) |
| SET(HAVE_OPENSL 0) |
| SET(HAVE_WAVE 0) |
| @@ -976,6 +977,17 @@ IF(ALSOFT_REQUIRE_OPENSL AND NOT HAVE_OPENSL) |
| MESSAGE(FATAL_ERROR "Failed to enabled required OpenSL backend") |
| ENDIF() |
| |
| +# Check PPAPI backend |
| +OPTION(PPAPI "Check for PPAPI backend" ON) |
| +IF (PPAPI) |
| + CHECK_INCLUDE_FILE(ppapi/c/ppb_audio.h HAVE_PPAPI_PPB_AUDIO_H) |
| + IF(HAVE_PPAPI_PPB_AUDIO_H) |
| + SET(HAVE_PPAPI 1) |
| + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/ppapi.c) |
| + SET(BACKENDS "${BACKENDS} PPAPI,") |
| + ENDIF() |
| +ENDIF() |
| + |
| # Optionally enable the Wave Writer backend |
| OPTION(ALSOFT_BACKEND_WAVE "Enable Wave Writer backend" ON) |
| IF(ALSOFT_BACKEND_WAVE) |
| @@ -1030,7 +1042,12 @@ CONFIGURE_FILE( |
| ADD_LIBRARY(common STATIC ${COMMON_OBJS}) |
| |
| # Build main library |
| -ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS}) |
| +IF(LIBTYPE STREQUAL "STATIC") |
| + ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS} ${COMMON_OBJS}) |
| +ELSE() |
| + ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS}) |
| +ENDIF() |
| + |
| SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES) |
| IF(WIN32 AND ALSOFT_NO_UID_DEFS) |
| SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS) |
| diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h |
| --- a/OpenAL32/Include/alMain.h |
| +++ b/OpenAL32/Include/alMain.h |
| @@ -273,6 +273,14 @@ typedef ptrdiff_t ALsizeiptrEXT; |
| #define U64(x) ((ALuint64)(x##ul)) |
| #elif SIZEOF_LONG_LONG == 8 |
| #define U64(x) ((ALuint64)(x##ull)) |
| +#elif defined(__WORDSIZE) |
| +#if __WORDSIZE == 64 |
| +#define U64(x) ((ALuint64)(x##ul)) |
| +#else |
| +#define U64(x) ((ALuint64)(x##ull)) |
| +#endif |
| +#else |
| +#error "unable to define U64" |
| #endif |
| #endif |
| |
| @@ -500,6 +508,9 @@ void alc_opensl_probe(enum DevProbe type); |
| ALCboolean alc_qsa_init(BackendFuncs *func_list); |
| void alc_qsa_deinit(void); |
| void alc_qsa_probe(enum DevProbe type); |
| +ALCboolean alc_ppapi_init(BackendFuncs *func_list); |
| +void alc_ppapi_deinit(void); |
| +void alc_ppapi_probe(enum DevProbe type); |
| |
| struct ALCbackend; |
| |
| @@ -549,7 +560,7 @@ enum DevFmtType { |
| DevFmtUInt = ALC_UNSIGNED_INT_SOFT, |
| DevFmtFloat = ALC_FLOAT_SOFT, |
| |
| - DevFmtTypeDefault = DevFmtFloat |
| + DevFmtTypeDefault = DevFmtShort |
| }; |
| enum DevFmtChannels { |
| DevFmtMono = ALC_MONO_SOFT, |
| diff --git a/config.h.in b/config.h.in |
| --- a/config.h.in |
| +++ b/config.h.in |
| @@ -70,6 +70,9 @@ |
| /* Define if we have the OpenSL backend */ |
| #cmakedefine HAVE_OPENSL |
| |
| +/* Define if we have the PPAPI backend */ |
| +#cmakedefine HAVE_PPAPI |
| + |
| /* Define if we have the Wave Writer backend */ |
| #cmakedefine HAVE_WAVE |
| |
| diff --git a/include/AL/alc.h b/include/AL/alc.h |
| --- a/include/AL/alc.h |
| +++ b/include/AL/alc.h |
| @@ -230,6 +230,15 @@ typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device); |
| typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device); |
| typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); |
| |
| +#if defined(__native_client__) |
| +#include <ppapi/c/ppp.h> |
| +#include <ppapi/c/ppp_instance.h> |
| +/* This function is part of the NaCl libopenal port and is |
| + * required to be called before OpenAL initialization. |
| + */ |
| +extern void alSetPpapiInfo(PP_Instance, PPB_GetInterface); |
| +#endif |
| + |
| #if defined(__cplusplus) |
| } |
| #endif |
| diff --git a/include/atomic.h b/include/atomic.h |
| --- a/include/atomic.h |
| +++ b/include/atomic.h |
| @@ -11,7 +11,7 @@ extern "C" { |
| typedef void *volatile XchgPtr; |
| |
| /* Atomics using C11 */ |
| -#ifdef HAVE_C11_ATOMIC |
| +#if defined(HAVE_C11_ATOMIC) && !defined(__native_client__) |
| |
| #include <stdatomic.h> |
| |