2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2000 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
36 #include "alc/context.h"
37 #include "alc/inprogext.h"
38 #include "alnumeric.h"
39 #include "aloptional.h"
41 #include "core/context.h"
42 #include "core/except.h"
43 #include "core/mixer/defs.h"
44 #include "core/voice.h"
45 #include "intrusive_ptr.h"
46 #include "opthelpers.h"
50 #include "alc/device.h"
52 #include "eax/globals.h"
53 #include "eax/x_ram.h"
59 constexpr ALchar alVendor[] = "OpenAL Community";
60 constexpr ALchar alVersion[] = "1.1 ALSOFT " ALSOFT_VERSION;
61 constexpr ALchar alRenderer[] = "OpenAL Soft";
64 constexpr ALchar alNoError[] = "No Error";
65 constexpr ALchar alErrInvalidName[] = "Invalid Name";
66 constexpr ALchar alErrInvalidEnum[] = "Invalid Enum";
67 constexpr ALchar alErrInvalidValue[] = "Invalid Value";
68 constexpr ALchar alErrInvalidOp[] = "Invalid Operation";
69 constexpr ALchar alErrOutOfMemory[] = "Out of Memory";
71 /* Resampler strings */
72 template<Resampler rtype> struct ResamplerName { };
73 template<> struct ResamplerName<Resampler::Point>
74 { static constexpr const ALchar *Get() noexcept { return "Nearest"; } };
75 template<> struct ResamplerName<Resampler::Linear>
76 { static constexpr const ALchar *Get() noexcept { return "Linear"; } };
77 template<> struct ResamplerName<Resampler::Cubic>
78 { static constexpr const ALchar *Get() noexcept { return "Cubic"; } };
79 template<> struct ResamplerName<Resampler::FastBSinc12>
80 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc (fast)"; } };
81 template<> struct ResamplerName<Resampler::BSinc12>
82 { static constexpr const ALchar *Get() noexcept { return "11th order Sinc"; } };
83 template<> struct ResamplerName<Resampler::FastBSinc24>
84 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc (fast)"; } };
85 template<> struct ResamplerName<Resampler::BSinc24>
86 { static constexpr const ALchar *Get() noexcept { return "23rd order Sinc"; } };
88 const ALchar *GetResamplerName(const Resampler rtype)
90 #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
93 HANDLE_RESAMPLER(Resampler::Point);
94 HANDLE_RESAMPLER(Resampler::Linear);
95 HANDLE_RESAMPLER(Resampler::Cubic);
96 HANDLE_RESAMPLER(Resampler::FastBSinc12);
97 HANDLE_RESAMPLER(Resampler::BSinc12);
98 HANDLE_RESAMPLER(Resampler::FastBSinc24);
99 HANDLE_RESAMPLER(Resampler::BSinc24);
101 #undef HANDLE_RESAMPLER
102 /* Should never get here. */
103 throw std::runtime_error{"Unexpected resampler index"};
106 al::optional<DistanceModel> DistanceModelFromALenum(ALenum model)
110 case AL_NONE: return DistanceModel::Disable;
111 case AL_INVERSE_DISTANCE: return DistanceModel::Inverse;
112 case AL_INVERSE_DISTANCE_CLAMPED: return DistanceModel::InverseClamped;
113 case AL_LINEAR_DISTANCE: return DistanceModel::Linear;
114 case AL_LINEAR_DISTANCE_CLAMPED: return DistanceModel::LinearClamped;
115 case AL_EXPONENT_DISTANCE: return DistanceModel::Exponent;
116 case AL_EXPONENT_DISTANCE_CLAMPED: return DistanceModel::ExponentClamped;
120 ALenum ALenumFromDistanceModel(DistanceModel model)
124 case DistanceModel::Disable: return AL_NONE;
125 case DistanceModel::Inverse: return AL_INVERSE_DISTANCE;
126 case DistanceModel::InverseClamped: return AL_INVERSE_DISTANCE_CLAMPED;
127 case DistanceModel::Linear: return AL_LINEAR_DISTANCE;
128 case DistanceModel::LinearClamped: return AL_LINEAR_DISTANCE_CLAMPED;
129 case DistanceModel::Exponent: return AL_EXPONENT_DISTANCE;
130 case DistanceModel::ExponentClamped: return AL_EXPONENT_DISTANCE_CLAMPED;
132 throw std::runtime_error{"Unexpected distance model "+std::to_string(static_cast<int>(model))};
137 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
140 AL_API const ALchar* AL_APIENTRY alsoft_get_version(void)
143 static const auto spoof = al::getenv("ALSOFT_SPOOF_VERSION");
144 if(spoof) return spoof->c_str();
145 return ALSOFT_VERSION;
149 #define DO_UPDATEPROPS() do { \
150 if(!context->mDeferUpdates) \
151 UpdateContextProps(context.get()); \
153 context->mPropsDirty = true; \
157 AL_API void AL_APIENTRY alEnable(ALenum capability)
160 ContextRef context{GetContextRef()};
161 if(!context) UNLIKELY return;
165 case AL_SOURCE_DISTANCE_MODEL:
167 std::lock_guard<std::mutex> _{context->mPropLock};
168 context->mSourceDistanceModel = true;
173 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
174 context->setError(AL_INVALID_OPERATION, "Re-enabling AL_STOP_SOURCES_ON_DISCONNECT_SOFT not yet supported");
178 context->setError(AL_INVALID_VALUE, "Invalid enable property 0x%04x", capability);
183 AL_API void AL_APIENTRY alDisable(ALenum capability)
186 ContextRef context{GetContextRef()};
187 if(!context) UNLIKELY return;
191 case AL_SOURCE_DISTANCE_MODEL:
193 std::lock_guard<std::mutex> _{context->mPropLock};
194 context->mSourceDistanceModel = false;
199 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
200 context->mStopVoicesOnDisconnect = false;
204 context->setError(AL_INVALID_VALUE, "Invalid disable property 0x%04x", capability);
209 AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability)
212 ContextRef context{GetContextRef()};
213 if(!context) UNLIKELY return AL_FALSE;
215 std::lock_guard<std::mutex> _{context->mPropLock};
216 ALboolean value{AL_FALSE};
219 case AL_SOURCE_DISTANCE_MODEL:
220 value = context->mSourceDistanceModel ? AL_TRUE : AL_FALSE;
223 case AL_STOP_SOURCES_ON_DISCONNECT_SOFT:
224 value = context->mStopVoicesOnDisconnect ? AL_TRUE : AL_FALSE;
228 context->setError(AL_INVALID_VALUE, "Invalid is enabled property 0x%04x", capability);
235 AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum pname)
238 ContextRef context{GetContextRef()};
239 if(!context) UNLIKELY return AL_FALSE;
241 std::lock_guard<std::mutex> _{context->mPropLock};
242 ALboolean value{AL_FALSE};
245 case AL_DOPPLER_FACTOR:
246 if(context->mDopplerFactor != 0.0f)
250 case AL_DOPPLER_VELOCITY:
251 if(context->mDopplerVelocity != 0.0f)
255 case AL_DISTANCE_MODEL:
256 if(context->mDistanceModel == DistanceModel::Default)
260 case AL_SPEED_OF_SOUND:
261 if(context->mSpeedOfSound != 0.0f)
265 case AL_DEFERRED_UPDATES_SOFT:
266 if(context->mDeferUpdates)
270 case AL_GAIN_LIMIT_SOFT:
271 if(GainMixMax/context->mGainBoost != 0.0f)
275 case AL_NUM_RESAMPLERS_SOFT:
280 case AL_DEFAULT_RESAMPLER_SOFT:
281 value = static_cast<int>(ResamplerDefault) ? AL_TRUE : AL_FALSE;
285 context->setError(AL_INVALID_VALUE, "Invalid boolean property 0x%04x", pname);
292 AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname)
295 ContextRef context{GetContextRef()};
296 if(!context) UNLIKELY return 0.0;
298 std::lock_guard<std::mutex> _{context->mPropLock};
302 case AL_DOPPLER_FACTOR:
303 value = context->mDopplerFactor;
306 case AL_DOPPLER_VELOCITY:
307 value = context->mDopplerVelocity;
310 case AL_DISTANCE_MODEL:
311 value = static_cast<ALdouble>(ALenumFromDistanceModel(context->mDistanceModel));
314 case AL_SPEED_OF_SOUND:
315 value = context->mSpeedOfSound;
318 case AL_DEFERRED_UPDATES_SOFT:
319 if(context->mDeferUpdates)
320 value = static_cast<ALdouble>(AL_TRUE);
323 case AL_GAIN_LIMIT_SOFT:
324 value = ALdouble{GainMixMax}/context->mGainBoost;
327 case AL_NUM_RESAMPLERS_SOFT:
328 value = static_cast<ALdouble>(Resampler::Max) + 1.0;
331 case AL_DEFAULT_RESAMPLER_SOFT:
332 value = static_cast<ALdouble>(ResamplerDefault);
336 context->setError(AL_INVALID_VALUE, "Invalid double property 0x%04x", pname);
343 AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname)
346 ContextRef context{GetContextRef()};
347 if(!context) UNLIKELY return 0.0f;
349 std::lock_guard<std::mutex> _{context->mPropLock};
353 case AL_DOPPLER_FACTOR:
354 value = context->mDopplerFactor;
357 case AL_DOPPLER_VELOCITY:
358 value = context->mDopplerVelocity;
361 case AL_DISTANCE_MODEL:
362 value = static_cast<ALfloat>(ALenumFromDistanceModel(context->mDistanceModel));
365 case AL_SPEED_OF_SOUND:
366 value = context->mSpeedOfSound;
369 case AL_DEFERRED_UPDATES_SOFT:
370 if(context->mDeferUpdates)
371 value = static_cast<ALfloat>(AL_TRUE);
374 case AL_GAIN_LIMIT_SOFT:
375 value = GainMixMax/context->mGainBoost;
378 case AL_NUM_RESAMPLERS_SOFT:
379 value = static_cast<ALfloat>(Resampler::Max) + 1.0f;
382 case AL_DEFAULT_RESAMPLER_SOFT:
383 value = static_cast<ALfloat>(ResamplerDefault);
387 context->setError(AL_INVALID_VALUE, "Invalid float property 0x%04x", pname);
394 AL_API ALint AL_APIENTRY alGetInteger(ALenum pname)
397 ContextRef context{GetContextRef()};
398 if(!context) UNLIKELY return 0;
400 std::lock_guard<std::mutex> _{context->mPropLock};
404 case AL_DOPPLER_FACTOR:
405 value = static_cast<ALint>(context->mDopplerFactor);
408 case AL_DOPPLER_VELOCITY:
409 value = static_cast<ALint>(context->mDopplerVelocity);
412 case AL_DISTANCE_MODEL:
413 value = ALenumFromDistanceModel(context->mDistanceModel);
416 case AL_SPEED_OF_SOUND:
417 value = static_cast<ALint>(context->mSpeedOfSound);
420 case AL_DEFERRED_UPDATES_SOFT:
421 if(context->mDeferUpdates)
425 case AL_GAIN_LIMIT_SOFT:
426 value = static_cast<ALint>(GainMixMax/context->mGainBoost);
429 case AL_NUM_RESAMPLERS_SOFT:
430 value = static_cast<int>(Resampler::Max) + 1;
433 case AL_DEFAULT_RESAMPLER_SOFT:
434 value = static_cast<int>(ResamplerDefault);
439 #define EAX_ERROR "[alGetInteger] EAX not enabled."
441 case AL_EAX_RAM_SIZE:
442 if (eax_g_is_enabled)
444 value = eax_x_ram_max_size;
448 context->setError(AL_INVALID_VALUE, EAX_ERROR);
453 case AL_EAX_RAM_FREE:
454 if (eax_g_is_enabled)
456 auto device = context->mALDevice.get();
457 std::lock_guard<std::mutex> device_lock{device->BufferLock};
459 value = static_cast<ALint>(device->eax_x_ram_free_size);
463 context->setError(AL_INVALID_VALUE, EAX_ERROR);
473 context->setError(AL_INVALID_VALUE, "Invalid integer property 0x%04x", pname);
480 AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname)
483 ContextRef context{GetContextRef()};
484 if(!context) UNLIKELY return 0_i64;
486 std::lock_guard<std::mutex> _{context->mPropLock};
487 ALint64SOFT value{0};
490 case AL_DOPPLER_FACTOR:
491 value = static_cast<ALint64SOFT>(context->mDopplerFactor);
494 case AL_DOPPLER_VELOCITY:
495 value = static_cast<ALint64SOFT>(context->mDopplerVelocity);
498 case AL_DISTANCE_MODEL:
499 value = ALenumFromDistanceModel(context->mDistanceModel);
502 case AL_SPEED_OF_SOUND:
503 value = static_cast<ALint64SOFT>(context->mSpeedOfSound);
506 case AL_DEFERRED_UPDATES_SOFT:
507 if(context->mDeferUpdates)
511 case AL_GAIN_LIMIT_SOFT:
512 value = static_cast<ALint64SOFT>(GainMixMax/context->mGainBoost);
515 case AL_NUM_RESAMPLERS_SOFT:
516 value = static_cast<ALint64SOFT>(Resampler::Max) + 1;
519 case AL_DEFAULT_RESAMPLER_SOFT:
520 value = static_cast<ALint64SOFT>(ResamplerDefault);
524 context->setError(AL_INVALID_VALUE, "Invalid integer64 property 0x%04x", pname);
531 AL_API ALvoid* AL_APIENTRY alGetPointerSOFT(ALenum pname)
534 ContextRef context{GetContextRef()};
535 if(!context) UNLIKELY return nullptr;
537 std::lock_guard<std::mutex> _{context->mPropLock};
538 void *value{nullptr};
541 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
542 value = reinterpret_cast<void*>(context->mEventCb);
545 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
546 value = context->mEventParam;
550 context->setError(AL_INVALID_VALUE, "Invalid pointer property 0x%04x", pname);
557 AL_API void AL_APIENTRY alGetBooleanv(ALenum pname, ALboolean *values)
564 case AL_DOPPLER_FACTOR:
565 case AL_DOPPLER_VELOCITY:
566 case AL_DISTANCE_MODEL:
567 case AL_SPEED_OF_SOUND:
568 case AL_DEFERRED_UPDATES_SOFT:
569 case AL_GAIN_LIMIT_SOFT:
570 case AL_NUM_RESAMPLERS_SOFT:
571 case AL_DEFAULT_RESAMPLER_SOFT:
572 values[0] = alGetBoolean(pname);
577 ContextRef context{GetContextRef()};
578 if(!context) UNLIKELY return;
581 context->setError(AL_INVALID_VALUE, "NULL pointer");
585 context->setError(AL_INVALID_VALUE, "Invalid boolean-vector property 0x%04x", pname);
590 AL_API void AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values)
597 case AL_DOPPLER_FACTOR:
598 case AL_DOPPLER_VELOCITY:
599 case AL_DISTANCE_MODEL:
600 case AL_SPEED_OF_SOUND:
601 case AL_DEFERRED_UPDATES_SOFT:
602 case AL_GAIN_LIMIT_SOFT:
603 case AL_NUM_RESAMPLERS_SOFT:
604 case AL_DEFAULT_RESAMPLER_SOFT:
605 values[0] = alGetDouble(pname);
610 ContextRef context{GetContextRef()};
611 if(!context) UNLIKELY return;
614 context->setError(AL_INVALID_VALUE, "NULL pointer");
618 context->setError(AL_INVALID_VALUE, "Invalid double-vector property 0x%04x", pname);
623 AL_API void AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values)
630 case AL_DOPPLER_FACTOR:
631 case AL_DOPPLER_VELOCITY:
632 case AL_DISTANCE_MODEL:
633 case AL_SPEED_OF_SOUND:
634 case AL_DEFERRED_UPDATES_SOFT:
635 case AL_GAIN_LIMIT_SOFT:
636 case AL_NUM_RESAMPLERS_SOFT:
637 case AL_DEFAULT_RESAMPLER_SOFT:
638 values[0] = alGetFloat(pname);
643 ContextRef context{GetContextRef()};
644 if(!context) UNLIKELY return;
647 context->setError(AL_INVALID_VALUE, "NULL pointer");
651 context->setError(AL_INVALID_VALUE, "Invalid float-vector property 0x%04x", pname);
656 AL_API void AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values)
663 case AL_DOPPLER_FACTOR:
664 case AL_DOPPLER_VELOCITY:
665 case AL_DISTANCE_MODEL:
666 case AL_SPEED_OF_SOUND:
667 case AL_DEFERRED_UPDATES_SOFT:
668 case AL_GAIN_LIMIT_SOFT:
669 case AL_NUM_RESAMPLERS_SOFT:
670 case AL_DEFAULT_RESAMPLER_SOFT:
671 values[0] = alGetInteger(pname);
676 ContextRef context{GetContextRef()};
677 if(!context) UNLIKELY return;
680 context->setError(AL_INVALID_VALUE, "NULL pointer");
684 context->setError(AL_INVALID_VALUE, "Invalid integer-vector property 0x%04x", pname);
689 AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values)
696 case AL_DOPPLER_FACTOR:
697 case AL_DOPPLER_VELOCITY:
698 case AL_DISTANCE_MODEL:
699 case AL_SPEED_OF_SOUND:
700 case AL_DEFERRED_UPDATES_SOFT:
701 case AL_GAIN_LIMIT_SOFT:
702 case AL_NUM_RESAMPLERS_SOFT:
703 case AL_DEFAULT_RESAMPLER_SOFT:
704 values[0] = alGetInteger64SOFT(pname);
709 ContextRef context{GetContextRef()};
710 if(!context) UNLIKELY return;
713 context->setError(AL_INVALID_VALUE, "NULL pointer");
717 context->setError(AL_INVALID_VALUE, "Invalid integer64-vector property 0x%04x", pname);
722 AL_API void AL_APIENTRY alGetPointervSOFT(ALenum pname, ALvoid **values)
729 case AL_EVENT_CALLBACK_FUNCTION_SOFT:
730 case AL_EVENT_CALLBACK_USER_PARAM_SOFT:
731 values[0] = alGetPointerSOFT(pname);
736 ContextRef context{GetContextRef()};
737 if(!context) UNLIKELY return;
740 context->setError(AL_INVALID_VALUE, "NULL pointer");
744 context->setError(AL_INVALID_VALUE, "Invalid pointer-vector property 0x%04x", pname);
749 AL_API const ALchar* AL_APIENTRY alGetString(ALenum pname)
752 ContextRef context{GetContextRef()};
753 if(!context) UNLIKELY return nullptr;
755 const ALchar *value{nullptr};
771 value = context->mExtensionList;
778 case AL_INVALID_NAME:
779 value = alErrInvalidName;
782 case AL_INVALID_ENUM:
783 value = alErrInvalidEnum;
786 case AL_INVALID_VALUE:
787 value = alErrInvalidValue;
790 case AL_INVALID_OPERATION:
791 value = alErrInvalidOp;
794 case AL_OUT_OF_MEMORY:
795 value = alErrOutOfMemory;
799 context->setError(AL_INVALID_VALUE, "Invalid string property 0x%04x", pname);
805 AL_API void AL_APIENTRY alDopplerFactor(ALfloat value)
808 ContextRef context{GetContextRef()};
809 if(!context) UNLIKELY return;
811 if(!(value >= 0.0f && std::isfinite(value)))
812 context->setError(AL_INVALID_VALUE, "Doppler factor %f out of range", value);
815 std::lock_guard<std::mutex> _{context->mPropLock};
816 context->mDopplerFactor = value;
822 AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value)
825 ContextRef context{GetContextRef()};
826 if(!context) UNLIKELY return;
828 if(!(value >= 0.0f && std::isfinite(value)))
829 context->setError(AL_INVALID_VALUE, "Doppler velocity %f out of range", value);
832 std::lock_guard<std::mutex> _{context->mPropLock};
833 context->mDopplerVelocity = value;
839 AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value)
842 ContextRef context{GetContextRef()};
843 if(!context) UNLIKELY return;
845 if(!(value > 0.0f && std::isfinite(value)))
846 context->setError(AL_INVALID_VALUE, "Speed of sound %f out of range", value);
849 std::lock_guard<std::mutex> _{context->mPropLock};
850 context->mSpeedOfSound = value;
856 AL_API void AL_APIENTRY alDistanceModel(ALenum value)
859 ContextRef context{GetContextRef()};
860 if(!context) UNLIKELY return;
862 if(auto model = DistanceModelFromALenum(value))
864 std::lock_guard<std::mutex> _{context->mPropLock};
865 context->mDistanceModel = *model;
866 if(!context->mSourceDistanceModel)
870 context->setError(AL_INVALID_VALUE, "Distance model 0x%04x out of range", value);
875 AL_API void AL_APIENTRY alDeferUpdatesSOFT(void)
878 ContextRef context{GetContextRef()};
879 if(!context) UNLIKELY return;
881 std::lock_guard<std::mutex> _{context->mPropLock};
882 context->deferUpdates();
886 AL_API void AL_APIENTRY alProcessUpdatesSOFT(void)
889 ContextRef context{GetContextRef()};
890 if(!context) UNLIKELY return;
892 std::lock_guard<std::mutex> _{context->mPropLock};
893 context->processUpdates();
898 AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index)
901 ContextRef context{GetContextRef()};
902 if(!context) UNLIKELY return nullptr;
904 const ALchar *value{nullptr};
907 case AL_RESAMPLER_NAME_SOFT:
908 if(index < 0 || index > static_cast<ALint>(Resampler::Max))
909 context->setError(AL_INVALID_VALUE, "Resampler name index %d out of range", index);
911 value = GetResamplerName(static_cast<Resampler>(index));
915 context->setError(AL_INVALID_VALUE, "Invalid string indexed property");
922 void UpdateContextProps(ALCcontext *context)
924 /* Get an unused proprty container, or allocate a new one as needed. */
925 ContextProps *props{context->mFreeContextProps.load(std::memory_order_acquire)};
927 props = new ContextProps{};
932 next = props->next.load(std::memory_order_relaxed);
933 } while(context->mFreeContextProps.compare_exchange_weak(props, next,
934 std::memory_order_seq_cst, std::memory_order_acquire) == 0);
937 /* Copy in current property values. */
938 ALlistener &listener = context->mListener;
939 props->Position = listener.Position;
940 props->Velocity = listener.Velocity;
941 props->OrientAt = listener.OrientAt;
942 props->OrientUp = listener.OrientUp;
943 props->Gain = listener.Gain;
944 props->MetersPerUnit = listener.mMetersPerUnit;
946 props->AirAbsorptionGainHF = context->mAirAbsorptionGainHF;
947 props->DopplerFactor = context->mDopplerFactor;
948 props->DopplerVelocity = context->mDopplerVelocity;
949 props->SpeedOfSound = context->mSpeedOfSound;
951 props->SourceDistanceModel = context->mSourceDistanceModel;
952 props->mDistanceModel = context->mDistanceModel;
954 /* Set the new container for updating internal parameters. */
955 props = context->mParams.ContextUpdate.exchange(props, std::memory_order_acq_rel);
958 /* If there was an unused update container, put it back in the
961 AtomicReplaceHead(context->mFreeContextProps, props);