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
35 #include "alcontext.h"
38 #include "alnumeric.h"
43 #include "inprogext.h"
44 #include "opthelpers.h"
50 constexpr ALchar alVendor
[] = "OpenAL Community";
51 constexpr ALchar alVersion
[] = "1.1 ALSOFT " ALSOFT_VERSION
;
52 constexpr ALchar alRenderer
[] = "OpenAL Soft";
55 constexpr ALchar alNoError
[] = "No Error";
56 constexpr ALchar alErrInvalidName
[] = "Invalid Name";
57 constexpr ALchar alErrInvalidEnum
[] = "Invalid Enum";
58 constexpr ALchar alErrInvalidValue
[] = "Invalid Value";
59 constexpr ALchar alErrInvalidOp
[] = "Invalid Operation";
60 constexpr ALchar alErrOutOfMemory
[] = "Out of Memory";
62 /* Resampler strings */
63 template<Resampler rtype
> struct ResamplerName
{ };
64 template<> struct ResamplerName
<Resampler::Point
>
65 { static const ALchar
*Get() noexcept
{ return "Nearest"; } };
66 template<> struct ResamplerName
<Resampler::Linear
>
67 { static const ALchar
*Get() noexcept
{ return "Linear"; } };
68 template<> struct ResamplerName
<Resampler::Cubic
>
69 { static const ALchar
*Get() noexcept
{ return "Cubic"; } };
70 template<> struct ResamplerName
<Resampler::FastBSinc12
>
71 { static const ALchar
*Get() noexcept
{ return "11th order Sinc (fast)"; } };
72 template<> struct ResamplerName
<Resampler::BSinc12
>
73 { static const ALchar
*Get() noexcept
{ return "11th order Sinc"; } };
74 template<> struct ResamplerName
<Resampler::FastBSinc24
>
75 { static const ALchar
*Get() noexcept
{ return "23rd order Sinc (fast)"; } };
76 template<> struct ResamplerName
<Resampler::BSinc24
>
77 { static const ALchar
*Get() noexcept
{ return "23rd order Sinc"; } };
79 const ALchar
*GetResamplerName(const Resampler rtype
) noexcept
81 #define HANDLE_RESAMPLER(r) case r: return ResamplerName<r>::Get()
84 HANDLE_RESAMPLER(Resampler::Point
);
85 HANDLE_RESAMPLER(Resampler::Linear
);
86 HANDLE_RESAMPLER(Resampler::Cubic
);
87 HANDLE_RESAMPLER(Resampler::FastBSinc12
);
88 HANDLE_RESAMPLER(Resampler::BSinc12
);
89 HANDLE_RESAMPLER(Resampler::FastBSinc24
);
90 HANDLE_RESAMPLER(Resampler::BSinc24
);
92 #undef HANDLE_RESAMPLER
97 /* WARNING: Non-standard export! Not part of any extension, or exposed in the
100 extern "C" AL_API
const ALchar
* AL_APIENTRY
alsoft_get_version(void)
103 static const auto spoof
= al::getenv("ALSOFT_SPOOF_VERSION");
104 if(spoof
) return spoof
->c_str();
105 return ALSOFT_VERSION
;
109 #define DO_UPDATEPROPS() do { \
110 if(!context->mDeferUpdates.load(std::memory_order_acquire)) \
111 UpdateContextProps(context.get()); \
113 context->mPropsClean.clear(std::memory_order_release); \
117 AL_API ALvoid AL_APIENTRY
alEnable(ALenum capability
)
120 ContextRef context
{GetContextRef()};
121 if UNLIKELY(!context
) return;
123 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
126 case AL_SOURCE_DISTANCE_MODEL
:
127 context
->mSourceDistanceModel
= AL_TRUE
;
132 context
->setError(AL_INVALID_VALUE
, "Invalid enable property 0x%04x", capability
);
137 AL_API ALvoid AL_APIENTRY
alDisable(ALenum capability
)
140 ContextRef context
{GetContextRef()};
141 if UNLIKELY(!context
) return;
143 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
146 case AL_SOURCE_DISTANCE_MODEL
:
147 context
->mSourceDistanceModel
= AL_FALSE
;
152 context
->setError(AL_INVALID_VALUE
, "Invalid disable property 0x%04x", capability
);
157 AL_API ALboolean AL_APIENTRY
alIsEnabled(ALenum capability
)
160 ContextRef context
{GetContextRef()};
161 if UNLIKELY(!context
) return AL_FALSE
;
163 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
164 ALboolean value
{AL_FALSE
};
167 case AL_SOURCE_DISTANCE_MODEL
:
168 value
= context
->mSourceDistanceModel
;
172 context
->setError(AL_INVALID_VALUE
, "Invalid is enabled property 0x%04x", capability
);
179 AL_API ALboolean AL_APIENTRY
alGetBoolean(ALenum pname
)
182 ContextRef context
{GetContextRef()};
183 if UNLIKELY(!context
) return AL_FALSE
;
185 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
186 ALboolean value
{AL_FALSE
};
189 case AL_DOPPLER_FACTOR
:
190 if(context
->mDopplerFactor
!= 0.0f
)
194 case AL_DOPPLER_VELOCITY
:
195 if(context
->mDopplerVelocity
!= 0.0f
)
199 case AL_DISTANCE_MODEL
:
200 if(context
->mDistanceModel
== DistanceModel::Default
)
204 case AL_SPEED_OF_SOUND
:
205 if(context
->mSpeedOfSound
!= 0.0f
)
209 case AL_DEFERRED_UPDATES_SOFT
:
210 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
214 case AL_GAIN_LIMIT_SOFT
:
215 if(GAIN_MIX_MAX
/context
->mGainBoost
!= 0.0f
)
219 case AL_NUM_RESAMPLERS_SOFT
:
224 case AL_DEFAULT_RESAMPLER_SOFT
:
225 value
= static_cast<int>(ResamplerDefault
) ? AL_TRUE
: AL_FALSE
;
229 context
->setError(AL_INVALID_VALUE
, "Invalid boolean property 0x%04x", pname
);
236 AL_API ALdouble AL_APIENTRY
alGetDouble(ALenum pname
)
239 ContextRef context
{GetContextRef()};
240 if UNLIKELY(!context
) return 0.0;
242 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
246 case AL_DOPPLER_FACTOR
:
247 value
= context
->mDopplerFactor
;
250 case AL_DOPPLER_VELOCITY
:
251 value
= context
->mDopplerVelocity
;
254 case AL_DISTANCE_MODEL
:
255 value
= static_cast<ALdouble
>(context
->mDistanceModel
);
258 case AL_SPEED_OF_SOUND
:
259 value
= context
->mSpeedOfSound
;
262 case AL_DEFERRED_UPDATES_SOFT
:
263 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
264 value
= static_cast<ALdouble
>(AL_TRUE
);
267 case AL_GAIN_LIMIT_SOFT
:
268 value
= ALdouble
{GAIN_MIX_MAX
}/context
->mGainBoost
;
271 case AL_NUM_RESAMPLERS_SOFT
:
272 value
= static_cast<ALdouble
>(Resampler::Max
) + 1.0;
275 case AL_DEFAULT_RESAMPLER_SOFT
:
276 value
= static_cast<ALdouble
>(ResamplerDefault
);
280 context
->setError(AL_INVALID_VALUE
, "Invalid double property 0x%04x", pname
);
287 AL_API ALfloat AL_APIENTRY
alGetFloat(ALenum pname
)
290 ContextRef context
{GetContextRef()};
291 if UNLIKELY(!context
) return 0.0f
;
293 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
297 case AL_DOPPLER_FACTOR
:
298 value
= context
->mDopplerFactor
;
301 case AL_DOPPLER_VELOCITY
:
302 value
= context
->mDopplerVelocity
;
305 case AL_DISTANCE_MODEL
:
306 value
= static_cast<ALfloat
>(context
->mDistanceModel
);
309 case AL_SPEED_OF_SOUND
:
310 value
= context
->mSpeedOfSound
;
313 case AL_DEFERRED_UPDATES_SOFT
:
314 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
315 value
= static_cast<ALfloat
>(AL_TRUE
);
318 case AL_GAIN_LIMIT_SOFT
:
319 value
= GAIN_MIX_MAX
/context
->mGainBoost
;
322 case AL_NUM_RESAMPLERS_SOFT
:
323 value
= static_cast<ALfloat
>(Resampler::Max
) + 1.0f
;
326 case AL_DEFAULT_RESAMPLER_SOFT
:
327 value
= static_cast<ALfloat
>(ResamplerDefault
);
331 context
->setError(AL_INVALID_VALUE
, "Invalid float property 0x%04x", pname
);
338 AL_API ALint AL_APIENTRY
alGetInteger(ALenum pname
)
341 ContextRef context
{GetContextRef()};
342 if UNLIKELY(!context
) return 0;
344 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
348 case AL_DOPPLER_FACTOR
:
349 value
= static_cast<ALint
>(context
->mDopplerFactor
);
352 case AL_DOPPLER_VELOCITY
:
353 value
= static_cast<ALint
>(context
->mDopplerVelocity
);
356 case AL_DISTANCE_MODEL
:
357 value
= static_cast<ALint
>(context
->mDistanceModel
);
360 case AL_SPEED_OF_SOUND
:
361 value
= static_cast<ALint
>(context
->mSpeedOfSound
);
364 case AL_DEFERRED_UPDATES_SOFT
:
365 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
369 case AL_GAIN_LIMIT_SOFT
:
370 value
= static_cast<ALint
>(GAIN_MIX_MAX
/context
->mGainBoost
);
373 case AL_NUM_RESAMPLERS_SOFT
:
374 value
= static_cast<int>(Resampler::Max
) + 1;
377 case AL_DEFAULT_RESAMPLER_SOFT
:
378 value
= static_cast<int>(ResamplerDefault
);
382 context
->setError(AL_INVALID_VALUE
, "Invalid integer property 0x%04x", pname
);
389 extern "C" AL_API ALint64SOFT AL_APIENTRY
alGetInteger64SOFT(ALenum pname
)
392 ContextRef context
{GetContextRef()};
393 if UNLIKELY(!context
) return 0_i64
;
395 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
396 ALint64SOFT value
{0};
399 case AL_DOPPLER_FACTOR
:
400 value
= static_cast<ALint64SOFT
>(context
->mDopplerFactor
);
403 case AL_DOPPLER_VELOCITY
:
404 value
= static_cast<ALint64SOFT
>(context
->mDopplerVelocity
);
407 case AL_DISTANCE_MODEL
:
408 value
= static_cast<ALint64SOFT
>(context
->mDistanceModel
);
411 case AL_SPEED_OF_SOUND
:
412 value
= static_cast<ALint64SOFT
>(context
->mSpeedOfSound
);
415 case AL_DEFERRED_UPDATES_SOFT
:
416 if(context
->mDeferUpdates
.load(std::memory_order_acquire
))
420 case AL_GAIN_LIMIT_SOFT
:
421 value
= static_cast<ALint64SOFT
>(GAIN_MIX_MAX
/context
->mGainBoost
);
424 case AL_NUM_RESAMPLERS_SOFT
:
425 value
= static_cast<ALint64SOFT
>(Resampler::Max
) + 1;
428 case AL_DEFAULT_RESAMPLER_SOFT
:
429 value
= static_cast<ALint64SOFT
>(ResamplerDefault
);
433 context
->setError(AL_INVALID_VALUE
, "Invalid integer64 property 0x%04x", pname
);
440 AL_API
void* AL_APIENTRY
alGetPointerSOFT(ALenum pname
)
443 ContextRef context
{GetContextRef()};
444 if UNLIKELY(!context
) return nullptr;
446 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
447 void *value
{nullptr};
450 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
451 value
= reinterpret_cast<void*>(context
->mEventCb
);
454 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
455 value
= context
->mEventParam
;
459 context
->setError(AL_INVALID_VALUE
, "Invalid pointer property 0x%04x", pname
);
466 AL_API ALvoid AL_APIENTRY
alGetBooleanv(ALenum pname
, ALboolean
*values
)
473 case AL_DOPPLER_FACTOR
:
474 case AL_DOPPLER_VELOCITY
:
475 case AL_DISTANCE_MODEL
:
476 case AL_SPEED_OF_SOUND
:
477 case AL_DEFERRED_UPDATES_SOFT
:
478 case AL_GAIN_LIMIT_SOFT
:
479 case AL_NUM_RESAMPLERS_SOFT
:
480 case AL_DEFAULT_RESAMPLER_SOFT
:
481 values
[0] = alGetBoolean(pname
);
486 ContextRef context
{GetContextRef()};
487 if UNLIKELY(!context
) return;
490 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
494 context
->setError(AL_INVALID_VALUE
, "Invalid boolean-vector property 0x%04x", pname
);
499 AL_API ALvoid AL_APIENTRY
alGetDoublev(ALenum pname
, ALdouble
*values
)
506 case AL_DOPPLER_FACTOR
:
507 case AL_DOPPLER_VELOCITY
:
508 case AL_DISTANCE_MODEL
:
509 case AL_SPEED_OF_SOUND
:
510 case AL_DEFERRED_UPDATES_SOFT
:
511 case AL_GAIN_LIMIT_SOFT
:
512 case AL_NUM_RESAMPLERS_SOFT
:
513 case AL_DEFAULT_RESAMPLER_SOFT
:
514 values
[0] = alGetDouble(pname
);
519 ContextRef context
{GetContextRef()};
520 if UNLIKELY(!context
) return;
523 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
527 context
->setError(AL_INVALID_VALUE
, "Invalid double-vector property 0x%04x", pname
);
532 AL_API ALvoid AL_APIENTRY
alGetFloatv(ALenum pname
, ALfloat
*values
)
539 case AL_DOPPLER_FACTOR
:
540 case AL_DOPPLER_VELOCITY
:
541 case AL_DISTANCE_MODEL
:
542 case AL_SPEED_OF_SOUND
:
543 case AL_DEFERRED_UPDATES_SOFT
:
544 case AL_GAIN_LIMIT_SOFT
:
545 case AL_NUM_RESAMPLERS_SOFT
:
546 case AL_DEFAULT_RESAMPLER_SOFT
:
547 values
[0] = alGetFloat(pname
);
552 ContextRef context
{GetContextRef()};
553 if UNLIKELY(!context
) return;
556 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
560 context
->setError(AL_INVALID_VALUE
, "Invalid float-vector property 0x%04x", pname
);
565 AL_API ALvoid AL_APIENTRY
alGetIntegerv(ALenum pname
, ALint
*values
)
572 case AL_DOPPLER_FACTOR
:
573 case AL_DOPPLER_VELOCITY
:
574 case AL_DISTANCE_MODEL
:
575 case AL_SPEED_OF_SOUND
:
576 case AL_DEFERRED_UPDATES_SOFT
:
577 case AL_GAIN_LIMIT_SOFT
:
578 case AL_NUM_RESAMPLERS_SOFT
:
579 case AL_DEFAULT_RESAMPLER_SOFT
:
580 values
[0] = alGetInteger(pname
);
585 ContextRef context
{GetContextRef()};
586 if UNLIKELY(!context
) return;
589 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
593 context
->setError(AL_INVALID_VALUE
, "Invalid integer-vector property 0x%04x", pname
);
598 extern "C" AL_API
void AL_APIENTRY
alGetInteger64vSOFT(ALenum pname
, ALint64SOFT
*values
)
605 case AL_DOPPLER_FACTOR
:
606 case AL_DOPPLER_VELOCITY
:
607 case AL_DISTANCE_MODEL
:
608 case AL_SPEED_OF_SOUND
:
609 case AL_DEFERRED_UPDATES_SOFT
:
610 case AL_GAIN_LIMIT_SOFT
:
611 case AL_NUM_RESAMPLERS_SOFT
:
612 case AL_DEFAULT_RESAMPLER_SOFT
:
613 values
[0] = alGetInteger64SOFT(pname
);
618 ContextRef context
{GetContextRef()};
619 if UNLIKELY(!context
) return;
622 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
626 context
->setError(AL_INVALID_VALUE
, "Invalid integer64-vector property 0x%04x", pname
);
631 AL_API
void AL_APIENTRY
alGetPointervSOFT(ALenum pname
, void **values
)
638 case AL_EVENT_CALLBACK_FUNCTION_SOFT
:
639 case AL_EVENT_CALLBACK_USER_PARAM_SOFT
:
640 values
[0] = alGetPointerSOFT(pname
);
645 ContextRef context
{GetContextRef()};
646 if UNLIKELY(!context
) return;
649 context
->setError(AL_INVALID_VALUE
, "NULL pointer");
653 context
->setError(AL_INVALID_VALUE
, "Invalid pointer-vector property 0x%04x", pname
);
658 AL_API
const ALchar
* AL_APIENTRY
alGetString(ALenum pname
)
661 ContextRef context
{GetContextRef()};
662 if UNLIKELY(!context
) return nullptr;
664 const ALchar
*value
{nullptr};
680 value
= context
->mExtensionList
;
687 case AL_INVALID_NAME
:
688 value
= alErrInvalidName
;
691 case AL_INVALID_ENUM
:
692 value
= alErrInvalidEnum
;
695 case AL_INVALID_VALUE
:
696 value
= alErrInvalidValue
;
699 case AL_INVALID_OPERATION
:
700 value
= alErrInvalidOp
;
703 case AL_OUT_OF_MEMORY
:
704 value
= alErrOutOfMemory
;
708 context
->setError(AL_INVALID_VALUE
, "Invalid string property 0x%04x", pname
);
714 AL_API ALvoid AL_APIENTRY
alDopplerFactor(ALfloat value
)
717 ContextRef context
{GetContextRef()};
718 if UNLIKELY(!context
) return;
720 if(!(value
>= 0.0f
&& std::isfinite(value
)))
721 context
->setError(AL_INVALID_VALUE
, "Doppler factor %f out of range", value
);
724 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
725 context
->mDopplerFactor
= value
;
731 AL_API ALvoid AL_APIENTRY
alDopplerVelocity(ALfloat value
)
734 ContextRef context
{GetContextRef()};
735 if UNLIKELY(!context
) return;
737 if((context
->mEnabledEvts
.load(std::memory_order_relaxed
)&EventType_Deprecated
))
739 std::lock_guard
<std::mutex
> _
{context
->mEventCbLock
};
740 ALbitfieldSOFT enabledevts
{context
->mEnabledEvts
.load(std::memory_order_relaxed
)};
741 if((enabledevts
&EventType_Deprecated
) && context
->mEventCb
)
743 static constexpr ALCchar msg
[] =
744 "alDopplerVelocity is deprecated in AL1.1, use alSpeedOfSound";
745 const ALsizei msglen
{sizeof(msg
)-1};
746 (*context
->mEventCb
)(AL_EVENT_TYPE_DEPRECATED_SOFT
, 0, 0, msglen
, msg
,
747 context
->mEventParam
);
751 if(!(value
>= 0.0f
&& std::isfinite(value
)))
752 context
->setError(AL_INVALID_VALUE
, "Doppler velocity %f out of range", value
);
755 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
756 context
->mDopplerVelocity
= value
;
762 AL_API ALvoid AL_APIENTRY
alSpeedOfSound(ALfloat value
)
765 ContextRef context
{GetContextRef()};
766 if UNLIKELY(!context
) return;
768 if(!(value
> 0.0f
&& std::isfinite(value
)))
769 context
->setError(AL_INVALID_VALUE
, "Speed of sound %f out of range", value
);
772 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
773 context
->mSpeedOfSound
= value
;
779 AL_API ALvoid AL_APIENTRY
alDistanceModel(ALenum value
)
782 ContextRef context
{GetContextRef()};
783 if UNLIKELY(!context
) return;
785 if(!(value
== AL_INVERSE_DISTANCE
|| value
== AL_INVERSE_DISTANCE_CLAMPED
||
786 value
== AL_LINEAR_DISTANCE
|| value
== AL_LINEAR_DISTANCE_CLAMPED
||
787 value
== AL_EXPONENT_DISTANCE
|| value
== AL_EXPONENT_DISTANCE_CLAMPED
||
789 context
->setError(AL_INVALID_VALUE
, "Distance model 0x%04x out of range", value
);
792 std::lock_guard
<std::mutex
> _
{context
->mPropLock
};
793 context
->mDistanceModel
= static_cast<DistanceModel
>(value
);
794 if(!context
->mSourceDistanceModel
)
801 AL_API ALvoid AL_APIENTRY
alDeferUpdatesSOFT(void)
804 ContextRef context
{GetContextRef()};
805 if UNLIKELY(!context
) return;
807 context
->deferUpdates();
811 AL_API ALvoid AL_APIENTRY
alProcessUpdatesSOFT(void)
814 ContextRef context
{GetContextRef()};
815 if UNLIKELY(!context
) return;
817 context
->processUpdates();
822 AL_API
const ALchar
* AL_APIENTRY
alGetStringiSOFT(ALenum pname
, ALsizei index
)
825 ContextRef context
{GetContextRef()};
826 if UNLIKELY(!context
) return nullptr;
828 const ALchar
*value
{nullptr};
831 case AL_RESAMPLER_NAME_SOFT
:
832 if(index
< 0 || index
> static_cast<ALint
>(Resampler::Max
))
833 context
->setError(AL_INVALID_VALUE
, "Resampler name index %d out of range", index
);
835 value
= GetResamplerName(static_cast<Resampler
>(index
));
839 context
->setError(AL_INVALID_VALUE
, "Invalid string indexed property");
846 void UpdateContextProps(ALCcontext
*context
)
848 /* Get an unused proprty container, or allocate a new one as needed. */
849 ALcontextProps
*props
{context
->mFreeContextProps
.load(std::memory_order_acquire
)};
851 props
= new ALcontextProps
{};
854 ALcontextProps
*next
;
856 next
= props
->next
.load(std::memory_order_relaxed
);
857 } while(context
->mFreeContextProps
.compare_exchange_weak(props
, next
,
858 std::memory_order_seq_cst
, std::memory_order_acquire
) == 0);
861 /* Copy in current property values. */
862 props
->DopplerFactor
= context
->mDopplerFactor
;
863 props
->DopplerVelocity
= context
->mDopplerVelocity
;
864 props
->SpeedOfSound
= context
->mSpeedOfSound
;
866 props
->SourceDistanceModel
= context
->mSourceDistanceModel
;
867 props
->mDistanceModel
= context
->mDistanceModel
;
869 /* Set the new container for updating internal parameters. */
870 props
= context
->mUpdate
.exchange(props
, std::memory_order_acq_rel
);
873 /* If there was an unused update container, put it back in the
876 AtomicReplaceHead(context
->mFreeContextProps
, props
);