Check for a minimum PipeWire version
[openal-soft.git] / al / listener.cpp
blob9484d9b1ac811567d229070aa690f5a8c7e29d86
1 /**
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
21 #include "config.h"
23 #include "listener.h"
25 #include <cmath>
26 #include <mutex>
28 #include "AL/al.h"
29 #include "AL/alc.h"
30 #include "AL/efx.h"
32 #include "alc/context.h"
33 #include "almalloc.h"
34 #include "atomic.h"
35 #include "core/except.h"
36 #include "opthelpers.h"
39 namespace {
41 inline void UpdateProps(ALCcontext *context)
43 if(!context->mDeferUpdates)
45 UpdateContextProps(context);
46 return;
48 context->mPropsDirty = true;
51 #ifdef ALSOFT_EAX
52 inline void CommitAndUpdateProps(ALCcontext *context)
54 if(!context->mDeferUpdates)
56 if(context->has_eax())
58 context->mHoldUpdates.store(true, std::memory_order_release);
59 while((context->mUpdateCount.load(std::memory_order_acquire)&1) != 0) {
60 /* busy-wait */
63 context->eax_commit_and_update_sources();
65 UpdateContextProps(context);
66 context->mHoldUpdates.store(false, std::memory_order_release);
67 return;
69 context->mPropsDirty = true;
72 #else
74 inline void CommitAndUpdateProps(ALCcontext *context)
75 { UpdateProps(context); }
76 #endif
78 } // namespace
80 AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value)
81 START_API_FUNC
83 ContextRef context{GetContextRef()};
84 if UNLIKELY(!context) return;
86 ALlistener &listener = context->mListener;
87 std::lock_guard<std::mutex> _{context->mPropLock};
88 switch(param)
90 case AL_GAIN:
91 if(!(value >= 0.0f && std::isfinite(value)))
92 SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener gain out of range");
93 listener.Gain = value;
94 UpdateProps(context.get());
95 break;
97 case AL_METERS_PER_UNIT:
98 if(!(value >= AL_MIN_METERS_PER_UNIT && value <= AL_MAX_METERS_PER_UNIT))
99 SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener meters per unit out of range");
100 listener.mMetersPerUnit = value;
101 UpdateProps(context.get());
102 break;
104 default:
105 context->setError(AL_INVALID_ENUM, "Invalid listener float property");
108 END_API_FUNC
110 AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3)
111 START_API_FUNC
113 ContextRef context{GetContextRef()};
114 if UNLIKELY(!context) return;
116 ALlistener &listener = context->mListener;
117 std::lock_guard<std::mutex> _{context->mPropLock};
118 switch(param)
120 case AL_POSITION:
121 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
122 SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener position out of range");
123 listener.Position[0] = value1;
124 listener.Position[1] = value2;
125 listener.Position[2] = value3;
126 CommitAndUpdateProps(context.get());
127 break;
129 case AL_VELOCITY:
130 if(!(std::isfinite(value1) && std::isfinite(value2) && std::isfinite(value3)))
131 SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener velocity out of range");
132 listener.Velocity[0] = value1;
133 listener.Velocity[1] = value2;
134 listener.Velocity[2] = value3;
135 CommitAndUpdateProps(context.get());
136 break;
138 default:
139 context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property");
142 END_API_FUNC
144 AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values)
145 START_API_FUNC
147 if(values)
149 switch(param)
151 case AL_GAIN:
152 case AL_METERS_PER_UNIT:
153 alListenerf(param, values[0]);
154 return;
156 case AL_POSITION:
157 case AL_VELOCITY:
158 alListener3f(param, values[0], values[1], values[2]);
159 return;
163 ContextRef context{GetContextRef()};
164 if UNLIKELY(!context) return;
166 ALlistener &listener = context->mListener;
167 std::lock_guard<std::mutex> _{context->mPropLock};
168 if(!values) SETERR_RETURN(context, AL_INVALID_VALUE,, "NULL pointer");
169 switch(param)
171 case AL_ORIENTATION:
172 if(!(std::isfinite(values[0]) && std::isfinite(values[1]) && std::isfinite(values[2]) &&
173 std::isfinite(values[3]) && std::isfinite(values[4]) && std::isfinite(values[5])))
174 SETERR_RETURN(context, AL_INVALID_VALUE,, "Listener orientation out of range");
175 /* AT then UP */
176 listener.OrientAt[0] = values[0];
177 listener.OrientAt[1] = values[1];
178 listener.OrientAt[2] = values[2];
179 listener.OrientUp[0] = values[3];
180 listener.OrientUp[1] = values[4];
181 listener.OrientUp[2] = values[5];
182 CommitAndUpdateProps(context.get());
183 break;
185 default:
186 context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property");
189 END_API_FUNC
192 AL_API void AL_APIENTRY alListeneri(ALenum param, ALint /*value*/)
193 START_API_FUNC
195 ContextRef context{GetContextRef()};
196 if UNLIKELY(!context) return;
198 std::lock_guard<std::mutex> _{context->mPropLock};
199 switch(param)
201 default:
202 context->setError(AL_INVALID_ENUM, "Invalid listener integer property");
205 END_API_FUNC
207 AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3)
208 START_API_FUNC
210 switch(param)
212 case AL_POSITION:
213 case AL_VELOCITY:
214 alListener3f(param, static_cast<ALfloat>(value1), static_cast<ALfloat>(value2), static_cast<ALfloat>(value3));
215 return;
218 ContextRef context{GetContextRef()};
219 if UNLIKELY(!context) return;
221 std::lock_guard<std::mutex> _{context->mPropLock};
222 switch(param)
224 default:
225 context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property");
228 END_API_FUNC
230 AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values)
231 START_API_FUNC
233 if(values)
235 ALfloat fvals[6];
236 switch(param)
238 case AL_POSITION:
239 case AL_VELOCITY:
240 alListener3f(param, static_cast<ALfloat>(values[0]), static_cast<ALfloat>(values[1]), static_cast<ALfloat>(values[2]));
241 return;
243 case AL_ORIENTATION:
244 fvals[0] = static_cast<ALfloat>(values[0]);
245 fvals[1] = static_cast<ALfloat>(values[1]);
246 fvals[2] = static_cast<ALfloat>(values[2]);
247 fvals[3] = static_cast<ALfloat>(values[3]);
248 fvals[4] = static_cast<ALfloat>(values[4]);
249 fvals[5] = static_cast<ALfloat>(values[5]);
250 alListenerfv(param, fvals);
251 return;
255 ContextRef context{GetContextRef()};
256 if UNLIKELY(!context) return;
258 std::lock_guard<std::mutex> _{context->mPropLock};
259 if(!values)
260 context->setError(AL_INVALID_VALUE, "NULL pointer");
261 else switch(param)
263 default:
264 context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property");
267 END_API_FUNC
270 AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value)
271 START_API_FUNC
273 ContextRef context{GetContextRef()};
274 if UNLIKELY(!context) return;
276 ALlistener &listener = context->mListener;
277 std::lock_guard<std::mutex> _{context->mPropLock};
278 if(!value)
279 context->setError(AL_INVALID_VALUE, "NULL pointer");
280 else switch(param)
282 case AL_GAIN:
283 *value = listener.Gain;
284 break;
286 case AL_METERS_PER_UNIT:
287 *value = listener.mMetersPerUnit;
288 break;
290 default:
291 context->setError(AL_INVALID_ENUM, "Invalid listener float property");
294 END_API_FUNC
296 AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3)
297 START_API_FUNC
299 ContextRef context{GetContextRef()};
300 if UNLIKELY(!context) return;
302 ALlistener &listener = context->mListener;
303 std::lock_guard<std::mutex> _{context->mPropLock};
304 if(!value1 || !value2 || !value3)
305 context->setError(AL_INVALID_VALUE, "NULL pointer");
306 else switch(param)
308 case AL_POSITION:
309 *value1 = listener.Position[0];
310 *value2 = listener.Position[1];
311 *value3 = listener.Position[2];
312 break;
314 case AL_VELOCITY:
315 *value1 = listener.Velocity[0];
316 *value2 = listener.Velocity[1];
317 *value3 = listener.Velocity[2];
318 break;
320 default:
321 context->setError(AL_INVALID_ENUM, "Invalid listener 3-float property");
324 END_API_FUNC
326 AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values)
327 START_API_FUNC
329 switch(param)
331 case AL_GAIN:
332 case AL_METERS_PER_UNIT:
333 alGetListenerf(param, values);
334 return;
336 case AL_POSITION:
337 case AL_VELOCITY:
338 alGetListener3f(param, values+0, values+1, values+2);
339 return;
342 ContextRef context{GetContextRef()};
343 if UNLIKELY(!context) return;
345 ALlistener &listener = context->mListener;
346 std::lock_guard<std::mutex> _{context->mPropLock};
347 if(!values)
348 context->setError(AL_INVALID_VALUE, "NULL pointer");
349 else switch(param)
351 case AL_ORIENTATION:
352 // AT then UP
353 values[0] = listener.OrientAt[0];
354 values[1] = listener.OrientAt[1];
355 values[2] = listener.OrientAt[2];
356 values[3] = listener.OrientUp[0];
357 values[4] = listener.OrientUp[1];
358 values[5] = listener.OrientUp[2];
359 break;
361 default:
362 context->setError(AL_INVALID_ENUM, "Invalid listener float-vector property");
365 END_API_FUNC
368 AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value)
369 START_API_FUNC
371 ContextRef context{GetContextRef()};
372 if UNLIKELY(!context) return;
374 std::lock_guard<std::mutex> _{context->mPropLock};
375 if(!value)
376 context->setError(AL_INVALID_VALUE, "NULL pointer");
377 else switch(param)
379 default:
380 context->setError(AL_INVALID_ENUM, "Invalid listener integer property");
383 END_API_FUNC
385 AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3)
386 START_API_FUNC
388 ContextRef context{GetContextRef()};
389 if UNLIKELY(!context) return;
391 ALlistener &listener = context->mListener;
392 std::lock_guard<std::mutex> _{context->mPropLock};
393 if(!value1 || !value2 || !value3)
394 context->setError(AL_INVALID_VALUE, "NULL pointer");
395 else switch(param)
397 case AL_POSITION:
398 *value1 = static_cast<ALint>(listener.Position[0]);
399 *value2 = static_cast<ALint>(listener.Position[1]);
400 *value3 = static_cast<ALint>(listener.Position[2]);
401 break;
403 case AL_VELOCITY:
404 *value1 = static_cast<ALint>(listener.Velocity[0]);
405 *value2 = static_cast<ALint>(listener.Velocity[1]);
406 *value3 = static_cast<ALint>(listener.Velocity[2]);
407 break;
409 default:
410 context->setError(AL_INVALID_ENUM, "Invalid listener 3-integer property");
413 END_API_FUNC
415 AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint* values)
416 START_API_FUNC
418 switch(param)
420 case AL_POSITION:
421 case AL_VELOCITY:
422 alGetListener3i(param, values+0, values+1, values+2);
423 return;
426 ContextRef context{GetContextRef()};
427 if UNLIKELY(!context) return;
429 ALlistener &listener = context->mListener;
430 std::lock_guard<std::mutex> _{context->mPropLock};
431 if(!values)
432 context->setError(AL_INVALID_VALUE, "NULL pointer");
433 else switch(param)
435 case AL_ORIENTATION:
436 // AT then UP
437 values[0] = static_cast<ALint>(listener.OrientAt[0]);
438 values[1] = static_cast<ALint>(listener.OrientAt[1]);
439 values[2] = static_cast<ALint>(listener.OrientAt[2]);
440 values[3] = static_cast<ALint>(listener.OrientUp[0]);
441 values[4] = static_cast<ALint>(listener.OrientUp[1]);
442 values[5] = static_cast<ALint>(listener.OrientUp[2]);
443 break;
445 default:
446 context->setError(AL_INVALID_ENUM, "Invalid listener integer-vector property");
449 END_API_FUNC