14 #include <string_view>
15 #include <unordered_map>
22 #include "alc/context.h"
23 #include "alc/device.h"
24 #include "alc/inprogext.h"
25 #include "alnumeric.h"
28 #include "auxeffectslot.h"
30 #include "core/logging.h"
31 #include "core/voice.h"
32 #include "direct_defs.h"
36 #include "intrusive_ptr.h"
37 #include "opthelpers.h"
41 /* Declared here to prevent compilers from thinking it should be inlined, which
42 * GCC warns about increasing code size.
44 DebugGroup::~DebugGroup() = default;
48 static_assert(DebugSeverityBase
+DebugSeverityCount
<= 32, "Too many debug bits");
50 template<typename T
, T
...Vals
>
51 constexpr auto make_array_sequence(std::integer_sequence
<T
, Vals
...>)
52 { return std::array
<T
,sizeof...(Vals
)>{Vals
...}; }
54 template<typename T
, size_t N
>
55 constexpr auto make_array_sequence()
56 { return make_array_sequence(std::make_integer_sequence
<T
,N
>{}); }
59 constexpr auto GetDebugSource(ALenum source
) noexcept
-> std::optional
<DebugSource
>
63 case AL_DEBUG_SOURCE_API_EXT
: return DebugSource::API
;
64 case AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT
: return DebugSource::System
;
65 case AL_DEBUG_SOURCE_THIRD_PARTY_EXT
: return DebugSource::ThirdParty
;
66 case AL_DEBUG_SOURCE_APPLICATION_EXT
: return DebugSource::Application
;
67 case AL_DEBUG_SOURCE_OTHER_EXT
: return DebugSource::Other
;
72 constexpr auto GetDebugType(ALenum type
) noexcept
-> std::optional
<DebugType
>
76 case AL_DEBUG_TYPE_ERROR_EXT
: return DebugType::Error
;
77 case AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT
: return DebugType::DeprecatedBehavior
;
78 case AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT
: return DebugType::UndefinedBehavior
;
79 case AL_DEBUG_TYPE_PORTABILITY_EXT
: return DebugType::Portability
;
80 case AL_DEBUG_TYPE_PERFORMANCE_EXT
: return DebugType::Performance
;
81 case AL_DEBUG_TYPE_MARKER_EXT
: return DebugType::Marker
;
82 case AL_DEBUG_TYPE_PUSH_GROUP_EXT
: return DebugType::PushGroup
;
83 case AL_DEBUG_TYPE_POP_GROUP_EXT
: return DebugType::PopGroup
;
84 case AL_DEBUG_TYPE_OTHER_EXT
: return DebugType::Other
;
89 constexpr auto GetDebugSeverity(ALenum severity
) noexcept
-> std::optional
<DebugSeverity
>
93 case AL_DEBUG_SEVERITY_HIGH_EXT
: return DebugSeverity::High
;
94 case AL_DEBUG_SEVERITY_MEDIUM_EXT
: return DebugSeverity::Medium
;
95 case AL_DEBUG_SEVERITY_LOW_EXT
: return DebugSeverity::Low
;
96 case AL_DEBUG_SEVERITY_NOTIFICATION_EXT
: return DebugSeverity::Notification
;
102 constexpr auto GetDebugSourceEnum(DebugSource source
) -> ALenum
106 case DebugSource::API
: return AL_DEBUG_SOURCE_API_EXT
;
107 case DebugSource::System
: return AL_DEBUG_SOURCE_AUDIO_SYSTEM_EXT
;
108 case DebugSource::ThirdParty
: return AL_DEBUG_SOURCE_THIRD_PARTY_EXT
;
109 case DebugSource::Application
: return AL_DEBUG_SOURCE_APPLICATION_EXT
;
110 case DebugSource::Other
: return AL_DEBUG_SOURCE_OTHER_EXT
;
112 throw std::runtime_error
{"Unexpected debug source value "+std::to_string(al::to_underlying(source
))};
115 constexpr auto GetDebugTypeEnum(DebugType type
) -> ALenum
119 case DebugType::Error
: return AL_DEBUG_TYPE_ERROR_EXT
;
120 case DebugType::DeprecatedBehavior
: return AL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_EXT
;
121 case DebugType::UndefinedBehavior
: return AL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_EXT
;
122 case DebugType::Portability
: return AL_DEBUG_TYPE_PORTABILITY_EXT
;
123 case DebugType::Performance
: return AL_DEBUG_TYPE_PERFORMANCE_EXT
;
124 case DebugType::Marker
: return AL_DEBUG_TYPE_MARKER_EXT
;
125 case DebugType::PushGroup
: return AL_DEBUG_TYPE_PUSH_GROUP_EXT
;
126 case DebugType::PopGroup
: return AL_DEBUG_TYPE_POP_GROUP_EXT
;
127 case DebugType::Other
: return AL_DEBUG_TYPE_OTHER_EXT
;
129 throw std::runtime_error
{"Unexpected debug type value "+std::to_string(al::to_underlying(type
))};
132 constexpr auto GetDebugSeverityEnum(DebugSeverity severity
) -> ALenum
136 case DebugSeverity::High
: return AL_DEBUG_SEVERITY_HIGH_EXT
;
137 case DebugSeverity::Medium
: return AL_DEBUG_SEVERITY_MEDIUM_EXT
;
138 case DebugSeverity::Low
: return AL_DEBUG_SEVERITY_LOW_EXT
;
139 case DebugSeverity::Notification
: return AL_DEBUG_SEVERITY_NOTIFICATION_EXT
;
141 throw std::runtime_error
{"Unexpected debug severity value "+std::to_string(al::to_underlying(severity
))};
145 constexpr auto GetDebugSourceName(DebugSource source
) noexcept
-> const char*
149 case DebugSource::API
: return "API";
150 case DebugSource::System
: return "Audio System";
151 case DebugSource::ThirdParty
: return "Third Party";
152 case DebugSource::Application
: return "Application";
153 case DebugSource::Other
: return "Other";
155 return "<invalid source>";
158 constexpr auto GetDebugTypeName(DebugType type
) noexcept
-> const char*
162 case DebugType::Error
: return "Error";
163 case DebugType::DeprecatedBehavior
: return "Deprecated Behavior";
164 case DebugType::UndefinedBehavior
: return "Undefined Behavior";
165 case DebugType::Portability
: return "Portability";
166 case DebugType::Performance
: return "Performance";
167 case DebugType::Marker
: return "Marker";
168 case DebugType::PushGroup
: return "Push Group";
169 case DebugType::PopGroup
: return "Pop Group";
170 case DebugType::Other
: return "Other";
172 return "<invalid type>";
175 constexpr auto GetDebugSeverityName(DebugSeverity severity
) noexcept
-> const char*
179 case DebugSeverity::High
: return "High";
180 case DebugSeverity::Medium
: return "Medium";
181 case DebugSeverity::Low
: return "Low";
182 case DebugSeverity::Notification
: return "Notification";
184 return "<invalid severity>";
190 void ALCcontext::sendDebugMessage(std::unique_lock
<std::mutex
> &debuglock
, DebugSource source
,
191 DebugType type
, ALuint id
, DebugSeverity severity
, std::string_view message
)
193 if(!mDebugEnabled
.load(std::memory_order_relaxed
)) UNLIKELY
196 if(message
.length() >= MaxDebugMessageLength
) UNLIKELY
198 ERR("Debug message too long (%zu >= %d):\n-> %.*s\n", message
.length(),
199 MaxDebugMessageLength
, al::sizei(message
), message
.data());
203 DebugGroup
&debug
= mDebugGroups
.back();
205 const uint64_t idfilter
{(1_u64
<< (DebugSourceBase
+al::to_underlying(source
)))
206 | (1_u64
<< (DebugTypeBase
+al::to_underlying(type
)))
207 | (uint64_t{id
} << 32)};
208 auto iditer
= std::lower_bound(debug
.mIdFilters
.cbegin(), debug
.mIdFilters
.cend(), idfilter
);
209 if(iditer
!= debug
.mIdFilters
.cend() && *iditer
== idfilter
)
212 const uint filter
{(1u << (DebugSourceBase
+al::to_underlying(source
)))
213 | (1u << (DebugTypeBase
+al::to_underlying(type
)))
214 | (1u << (DebugSeverityBase
+al::to_underlying(severity
)))};
215 auto iter
= std::lower_bound(debug
.mFilters
.cbegin(), debug
.mFilters
.cend(), filter
);
216 if(iter
!= debug
.mFilters
.cend() && *iter
== filter
)
221 auto callback
= mDebugCb
;
222 auto param
= mDebugParam
;
224 callback(GetDebugSourceEnum(source
), GetDebugTypeEnum(type
), id
,
225 GetDebugSeverityEnum(severity
), static_cast<ALsizei
>(message
.length()), message
.data(),
230 if(mDebugLog
.size() < MaxDebugLoggedMessages
)
231 mDebugLog
.emplace_back(source
, type
, id
, severity
, message
);
233 ERR("Debug message log overflow. Lost message:\n"
238 " Message: \"%.*s\"\n",
239 GetDebugSourceName(source
), GetDebugTypeName(type
), id
,
240 GetDebugSeverityName(severity
), al::sizei(message
), message
.data());
245 FORCE_ALIGN
DECL_FUNCEXT2(void, alDebugMessageCallback
,EXT
, ALDEBUGPROCEXT
,callback
, void*,userParam
)
246 FORCE_ALIGN
void AL_APIENTRY
alDebugMessageCallbackDirectEXT(ALCcontext
*context
,
247 ALDEBUGPROCEXT callback
, void *userParam
) noexcept
249 std::lock_guard
<std::mutex
> debuglock
{context
->mDebugCbLock
};
250 context
->mDebugCb
= callback
;
251 context
->mDebugParam
= userParam
;
255 FORCE_ALIGN
DECL_FUNCEXT6(void, alDebugMessageInsert
,EXT
, ALenum
,source
, ALenum
,type
, ALuint
,id
, ALenum
,severity
, ALsizei
,length
, const ALchar
*,message
)
256 FORCE_ALIGN
void AL_APIENTRY
alDebugMessageInsertDirectEXT(ALCcontext
*context
, ALenum source
,
257 ALenum type
, ALuint id
, ALenum severity
, ALsizei length
, const ALchar
*message
) noexcept
259 if(!context
->mContextFlags
.test(ContextFlags::DebugBit
))
263 throw al::context_error
{AL_INVALID_VALUE
, "Null message pointer"};
265 auto msgview
= (length
< 0) ? std::string_view
{message
}
266 : std::string_view
{message
, static_cast<uint
>(length
)};
267 if(msgview
.size() >= MaxDebugMessageLength
)
268 throw al::context_error
{AL_INVALID_VALUE
, "Debug message too long (%zu >= %d)",
269 msgview
.size(), MaxDebugMessageLength
};
271 auto dsource
= GetDebugSource(source
);
273 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug source 0x%04x", source
};
274 if(*dsource
!= DebugSource::ThirdParty
&& *dsource
!= DebugSource::Application
)
275 throw al::context_error
{AL_INVALID_ENUM
, "Debug source 0x%04x not allowed", source
};
277 auto dtype
= GetDebugType(type
);
279 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug type 0x%04x", type
};
281 auto dseverity
= GetDebugSeverity(severity
);
283 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug severity 0x%04x", severity
};
285 context
->debugMessage(*dsource
, *dtype
, id
, *dseverity
, msgview
);
287 catch(al::context_error
& e
) {
288 context
->setError(e
.errorCode(), "%s", e
.what());
292 FORCE_ALIGN
DECL_FUNCEXT6(void, alDebugMessageControl
,EXT
, ALenum
,source
, ALenum
,type
, ALenum
,severity
, ALsizei
,count
, const ALuint
*,ids
, ALboolean
,enable
)
293 FORCE_ALIGN
void AL_APIENTRY
alDebugMessageControlDirectEXT(ALCcontext
*context
, ALenum source
,
294 ALenum type
, ALenum severity
, ALsizei count
, const ALuint
*ids
, ALboolean enable
) noexcept
299 throw al::context_error
{AL_INVALID_VALUE
, "IDs is null with non-0 count"};
300 if(source
== AL_DONT_CARE_EXT
)
301 throw al::context_error
{AL_INVALID_OPERATION
,
302 "Debug source cannot be AL_DONT_CARE_EXT with IDs"};
303 if(type
== AL_DONT_CARE_EXT
)
304 throw al::context_error
{AL_INVALID_OPERATION
,
305 "Debug type cannot be AL_DONT_CARE_EXT with IDs"};
306 if(severity
!= AL_DONT_CARE_EXT
)
307 throw al::context_error
{AL_INVALID_OPERATION
,
308 "Debug severity must be AL_DONT_CARE_EXT with IDs"};
311 if(enable
!= AL_TRUE
&& enable
!= AL_FALSE
)
312 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug enable %d", enable
};
314 static constexpr size_t ElemCount
{DebugSourceCount
+ DebugTypeCount
+ DebugSeverityCount
};
315 static constexpr auto Values
= make_array_sequence
<uint8_t,ElemCount
>();
317 auto srcIndices
= al::span
{Values
}.subspan(DebugSourceBase
,DebugSourceCount
);
318 if(source
!= AL_DONT_CARE_EXT
)
320 auto dsource
= GetDebugSource(source
);
322 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug source 0x%04x", source
};
323 srcIndices
= srcIndices
.subspan(al::to_underlying(*dsource
), 1);
326 auto typeIndices
= al::span
{Values
}.subspan(DebugTypeBase
,DebugTypeCount
);
327 if(type
!= AL_DONT_CARE_EXT
)
329 auto dtype
= GetDebugType(type
);
331 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug type 0x%04x", type
};
332 typeIndices
= typeIndices
.subspan(al::to_underlying(*dtype
), 1);
335 auto svrIndices
= al::span
{Values
}.subspan(DebugSeverityBase
,DebugSeverityCount
);
336 if(severity
!= AL_DONT_CARE_EXT
)
338 auto dseverity
= GetDebugSeverity(severity
);
340 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug severity 0x%04x", severity
};
341 svrIndices
= svrIndices
.subspan(al::to_underlying(*dseverity
), 1);
344 std::lock_guard
<std::mutex
> debuglock
{context
->mDebugCbLock
};
345 DebugGroup
&debug
= context
->mDebugGroups
.back();
348 const uint filterbase
{(1u<<srcIndices
[0]) | (1u<<typeIndices
[0])};
350 for(const uint id
: al::span
{ids
, static_cast<uint
>(count
)})
352 const uint64_t filter
{filterbase
| (uint64_t{id
} << 32)};
354 auto iter
= std::lower_bound(debug
.mIdFilters
.cbegin(), debug
.mIdFilters
.cend(),
356 if(!enable
&& (iter
== debug
.mIdFilters
.cend() || *iter
!= filter
))
357 debug
.mIdFilters
.insert(iter
, filter
);
358 else if(enable
&& iter
!= debug
.mIdFilters
.cend() && *iter
== filter
)
359 debug
.mIdFilters
.erase(iter
);
364 auto apply_filter
= [enable
,&debug
](const uint filter
)
366 auto iter
= std::lower_bound(debug
.mFilters
.cbegin(), debug
.mFilters
.cend(), filter
);
367 if(!enable
&& (iter
== debug
.mFilters
.cend() || *iter
!= filter
))
368 debug
.mFilters
.insert(iter
, filter
);
369 else if(enable
&& iter
!= debug
.mFilters
.cend() && *iter
== filter
)
370 debug
.mFilters
.erase(iter
);
372 auto apply_severity
= [apply_filter
,svrIndices
](const uint filter
)
374 std::for_each(svrIndices
.cbegin(), svrIndices
.cend(),
375 [apply_filter
,filter
](const uint idx
){ apply_filter(filter
| (1<<idx
)); });
377 auto apply_type
= [apply_severity
,typeIndices
](const uint filter
)
379 std::for_each(typeIndices
.cbegin(), typeIndices
.cend(),
380 [apply_severity
,filter
](const uint idx
){ apply_severity(filter
| (1<<idx
)); });
382 std::for_each(srcIndices
.cbegin(), srcIndices
.cend(),
383 [apply_type
](const uint idx
){ apply_type(1<<idx
); });
386 catch(al::context_error
& e
) {
387 context
->setError(e
.errorCode(), "%s", e
.what());
391 FORCE_ALIGN
DECL_FUNCEXT4(void, alPushDebugGroup
,EXT
, ALenum
,source
, ALuint
,id
, ALsizei
,length
, const ALchar
*,message
)
392 FORCE_ALIGN
void AL_APIENTRY
alPushDebugGroupDirectEXT(ALCcontext
*context
, ALenum source
,
393 ALuint id
, ALsizei length
, const ALchar
*message
) noexcept
397 size_t newlen
{std::strlen(message
)};
398 if(newlen
>= MaxDebugMessageLength
)
399 throw al::context_error
{AL_INVALID_VALUE
, "Debug message too long (%zu >= %d)", newlen
,
400 MaxDebugMessageLength
};
401 length
= static_cast<ALsizei
>(newlen
);
403 else if(length
>= MaxDebugMessageLength
)
404 throw al::context_error
{AL_INVALID_VALUE
, "Debug message too long (%d >= %d)", length
,
405 MaxDebugMessageLength
};
407 auto dsource
= GetDebugSource(source
);
409 throw al::context_error
{AL_INVALID_ENUM
, "Invalid debug source 0x%04x", source
};
410 if(*dsource
!= DebugSource::ThirdParty
&& *dsource
!= DebugSource::Application
)
411 throw al::context_error
{AL_INVALID_ENUM
, "Debug source 0x%04x not allowed", source
};
413 std::unique_lock
<std::mutex
> debuglock
{context
->mDebugCbLock
};
414 if(context
->mDebugGroups
.size() >= MaxDebugGroupDepth
)
415 throw al::context_error
{AL_STACK_OVERFLOW_EXT
, "Pushing too many debug groups"};
417 context
->mDebugGroups
.emplace_back(*dsource
, id
,
418 std::string_view
{message
, static_cast<uint
>(length
)});
419 auto &oldback
= *(context
->mDebugGroups
.end()-2);
420 auto &newback
= context
->mDebugGroups
.back();
422 newback
.mFilters
= oldback
.mFilters
;
423 newback
.mIdFilters
= oldback
.mIdFilters
;
425 if(context
->mContextFlags
.test(ContextFlags::DebugBit
))
426 context
->sendDebugMessage(debuglock
, newback
.mSource
, DebugType::PushGroup
, newback
.mId
,
427 DebugSeverity::Notification
, newback
.mMessage
);
429 catch(al::context_error
& e
) {
430 context
->setError(e
.errorCode(), "%s", e
.what());
433 FORCE_ALIGN
DECL_FUNCEXT(void, alPopDebugGroup
,EXT
)
434 FORCE_ALIGN
void AL_APIENTRY
alPopDebugGroupDirectEXT(ALCcontext
*context
) noexcept
436 std::unique_lock
<std::mutex
> debuglock
{context
->mDebugCbLock
};
437 if(context
->mDebugGroups
.size() <= 1)
438 throw al::context_error
{AL_STACK_UNDERFLOW_EXT
,
439 "Attempting to pop the default debug group"};
441 DebugGroup
&debug
= context
->mDebugGroups
.back();
442 const auto source
= debug
.mSource
;
443 const auto id
= debug
.mId
;
444 std::string message
{std::move(debug
.mMessage
)};
446 context
->mDebugGroups
.pop_back();
447 if(context
->mContextFlags
.test(ContextFlags::DebugBit
))
448 context
->sendDebugMessage(debuglock
, source
, DebugType::PopGroup
, id
,
449 DebugSeverity::Notification
, message
);
451 catch(al::context_error
& e
) {
452 context
->setError(e
.errorCode(), "%s", e
.what());
456 FORCE_ALIGN
DECL_FUNCEXT8(ALuint
, alGetDebugMessageLog
,EXT
, ALuint
,count
, ALsizei
,logBufSize
, ALenum
*,sources
, ALenum
*,types
, ALuint
*,ids
, ALenum
*,severities
, ALsizei
*,lengths
, ALchar
*,logBuf
)
457 FORCE_ALIGN ALuint AL_APIENTRY
alGetDebugMessageLogDirectEXT(ALCcontext
*context
, ALuint count
,
458 ALsizei logBufSize
, ALenum
*sources
, ALenum
*types
, ALuint
*ids
, ALenum
*severities
,
459 ALsizei
*lengths
, ALchar
*logBuf
) noexcept
462 throw al::context_error
{AL_INVALID_VALUE
, "Negative debug log buffer size"};
464 auto sourcesOut
= al::span
{sources
, sources
? count
: 0u};
465 auto typesOut
= al::span
{types
, types
? count
: 0u};
466 auto idsOut
= al::span
{ids
, ids
? count
: 0u};
467 auto severitiesOut
= al::span
{severities
, severities
? count
: 0u};
468 auto lengthsOut
= al::span
{lengths
, lengths
? count
: 0u};
469 auto logOut
= al::span
{logBuf
, logBuf
? static_cast<ALuint
>(logBufSize
) : 0u};
471 std::lock_guard
<std::mutex
> debuglock
{context
->mDebugCbLock
};
472 for(ALuint i
{0};i
< count
;++i
)
474 if(context
->mDebugLog
.empty())
477 auto &entry
= context
->mDebugLog
.front();
478 const size_t tocopy
{entry
.mMessage
.size() + 1};
479 if(logOut
.data() != nullptr)
481 if(logOut
.size() < tocopy
)
483 auto oiter
= std::copy(entry
.mMessage
.cbegin(), entry
.mMessage
.cend(), logOut
.begin());
485 logOut
= {oiter
+1, logOut
.end()};
488 if(!sourcesOut
.empty())
490 sourcesOut
.front() = GetDebugSourceEnum(entry
.mSource
);
491 sourcesOut
= sourcesOut
.subspan
<1>();
493 if(!typesOut
.empty())
495 typesOut
.front() = GetDebugTypeEnum(entry
.mType
);
496 typesOut
= typesOut
.subspan
<1>();
500 idsOut
.front() = entry
.mId
;
501 idsOut
= idsOut
.subspan
<1>();
503 if(!severitiesOut
.empty())
505 severitiesOut
.front() = GetDebugSeverityEnum(entry
.mSeverity
);
506 severitiesOut
= severitiesOut
.subspan
<1>();
508 if(!lengthsOut
.empty())
510 lengthsOut
.front() = static_cast<ALsizei
>(tocopy
);
511 lengthsOut
= lengthsOut
.subspan
<1>();
514 context
->mDebugLog
.pop_front();
519 catch(al::context_error
& e
) {
520 context
->setError(e
.errorCode(), "%s", e
.what());
524 FORCE_ALIGN
DECL_FUNCEXT4(void, alObjectLabel
,EXT
, ALenum
,identifier
, ALuint
,name
, ALsizei
,length
, const ALchar
*,label
)
525 FORCE_ALIGN
void AL_APIENTRY
alObjectLabelDirectEXT(ALCcontext
*context
, ALenum identifier
,
526 ALuint name
, ALsizei length
, const ALchar
*label
) noexcept
528 if(!label
&& length
!= 0)
529 throw al::context_error
{AL_INVALID_VALUE
, "Null label pointer"};
531 auto objname
= (length
< 0) ? std::string_view
{label
}
532 : std::string_view
{label
, static_cast<uint
>(length
)};
533 if(objname
.size() >= MaxObjectLabelLength
)
534 throw al::context_error
{AL_INVALID_VALUE
, "Object label length too long (%zu >= %d)",
535 objname
.size(), MaxObjectLabelLength
};
539 case AL_SOURCE_EXT
: ALsource::SetName(context
, name
, objname
); return;
540 case AL_BUFFER
: ALbuffer::SetName(context
, name
, objname
); return;
541 case AL_FILTER_EXT
: ALfilter::SetName(context
, name
, objname
); return;
542 case AL_EFFECT_EXT
: ALeffect::SetName(context
, name
, objname
); return;
543 case AL_AUXILIARY_EFFECT_SLOT_EXT
: ALeffectslot::SetName(context
, name
, objname
); return;
546 throw al::context_error
{AL_INVALID_ENUM
, "Invalid name identifier 0x%04x", identifier
};
548 catch(al::context_error
& e
) {
549 context
->setError(e
.errorCode(), "%s", e
.what());
552 FORCE_ALIGN
DECL_FUNCEXT5(void, alGetObjectLabel
,EXT
, ALenum
,identifier
, ALuint
,name
, ALsizei
,bufSize
, ALsizei
*,length
, ALchar
*,label
)
553 FORCE_ALIGN
void AL_APIENTRY
alGetObjectLabelDirectEXT(ALCcontext
*context
, ALenum identifier
,
554 ALuint name
, ALsizei bufSize
, ALsizei
*length
, ALchar
*label
) noexcept
557 throw al::context_error
{AL_INVALID_VALUE
, "Negative label bufSize"};
559 if(!label
&& !length
)
560 throw al::context_error
{AL_INVALID_VALUE
, "Null length and label"};
561 if(label
&& bufSize
== 0)
562 throw al::context_error
{AL_INVALID_VALUE
, "Zero label bufSize"};
564 const auto labelOut
= al::span
{label
, label
? static_cast<ALuint
>(bufSize
) : 0u};
565 auto copy_name
= [name
,length
,labelOut
](std::unordered_map
<ALuint
,std::string
> &names
)
567 std::string_view objname
;
569 auto iter
= names
.find(name
);
570 if(iter
!= names
.end())
571 objname
= iter
->second
;
574 *length
= static_cast<ALsizei
>(objname
.size());
577 const size_t tocopy
{std::min(objname
.size(), labelOut
.size()-1)};
578 auto oiter
= std::copy_n(objname
.cbegin(), tocopy
, labelOut
.begin());
581 *length
= static_cast<ALsizei
>(tocopy
);
585 if(identifier
== AL_SOURCE_EXT
)
587 std::lock_guard srclock
{context
->mSourceLock
};
588 copy_name(context
->mSourceNames
);
590 else if(identifier
== AL_BUFFER
)
592 ALCdevice
*device
{context
->mALDevice
.get()};
593 std::lock_guard buflock
{device
->BufferLock
};
594 copy_name(device
->mBufferNames
);
596 else if(identifier
== AL_FILTER_EXT
)
598 ALCdevice
*device
{context
->mALDevice
.get()};
599 std::lock_guard filterlock
{device
->FilterLock
};
600 copy_name(device
->mFilterNames
);
602 else if(identifier
== AL_EFFECT_EXT
)
604 ALCdevice
*device
{context
->mALDevice
.get()};
605 std::lock_guard effectlock
{device
->EffectLock
};
606 copy_name(device
->mEffectNames
);
608 else if(identifier
== AL_AUXILIARY_EFFECT_SLOT_EXT
)
610 std::lock_guard slotlock
{context
->mEffectSlotLock
};
611 copy_name(context
->mEffectSlotNames
);
614 throw al::context_error
{AL_INVALID_ENUM
, "Invalid name identifier 0x%04x", identifier
};
616 catch(al::context_error
& e
) {
617 context
->setError(e
.errorCode(), "%s", e
.what());