14 #include "devicemanager.h"
23 static inline void LoadALCFunc(ALCdevice
*device
, T
**func
, const char *name
)
24 { *func
= reinterpret_cast<T
*>(alcGetProcAddress(device
, name
)); }
27 static void LoadPauseDevice(ALDevice
*device
)
29 LoadALCFunc(device
->getDevice(), &device
->alcDevicePauseSOFT
, "alcDevicePauseSOFT");
30 LoadALCFunc(device
->getDevice(), &device
->alcDeviceResumeSOFT
, "alcDeviceResumeSOFT");
33 static void LoadHrtf(ALDevice
*device
)
35 LoadALCFunc(device
->getDevice(), &device
->alcGetStringiSOFT
, "alcGetStringiSOFT");
36 LoadALCFunc(device
->getDevice(), &device
->alcResetDeviceSOFT
, "alcResetDeviceSOFT");
39 static void LoadNothing(ALDevice
*) { }
42 enum ALCExtension extension
;
44 void (&loader
)(ALDevice
*);
45 } ALCExtensionList
[] = {
46 { EXT_thread_local_context
, "ALC_EXT_thread_local_context", LoadNothing
},
47 { SOFT_device_pause
, "ALC_SOFT_pause_device", LoadPauseDevice
},
48 { SOFT_HRTF
, "ALC_SOFT_HRTF", LoadHrtf
},
52 void ALDevice::setupExts()
54 std::fill(std::begin(mHasExt
), std::end(mHasExt
), false);
55 for(const auto &entry
: ALCExtensionList
)
57 mHasExt
[entry
.extension
] = alcIsExtensionPresent(mDevice
, entry
.name
);
58 if(mHasExt
[entry
.extension
]) entry
.loader(this);
63 ALDevice::ALDevice(ALCdevice
* device
)
64 : mDevice(device
), alcDevicePauseSOFT(nullptr), alcDeviceResumeSOFT(nullptr)
74 void ALDevice::removeContext(ALContext
*ctx
)
76 auto iter
= std::find_if(mContexts
.begin(), mContexts
.end(),
77 [ctx
](const UniquePtr
<ALContext
> &entry
) -> bool
78 { return entry
.get() == ctx
; }
80 if(iter
!= mContexts
.end()) mContexts
.erase(iter
);
84 String
ALDevice::getName(PlaybackName type
) const
86 if(type
== PlaybackName::Full
&& !alcIsExtensionPresent(mDevice
, "ALC_ENUMERATE_ALL_EXT"))
87 type
= PlaybackName::Basic
;
89 const ALCchar
*name
= alcGetString(mDevice
, (ALenum
)type
);
90 if(alcGetError(mDevice
) != ALC_NO_ERROR
|| !name
)
91 name
= alcGetString(mDevice
, (ALenum
)PlaybackName::Basic
);
92 return name
? String(name
) : String();
95 bool ALDevice::queryExtension(const String
&name
) const
97 return alcIsExtensionPresent(mDevice
, name
.c_str());
100 ALCuint
ALDevice::getALCVersion() const
102 ALCint major
=-1, minor
=-1;
103 alcGetIntegerv(mDevice
, ALC_MAJOR_VERSION
, 1, &major
);
104 alcGetIntegerv(mDevice
, ALC_MINOR_VERSION
, 1, &minor
);
105 if(major
< 0 || minor
< 0)
106 throw std::runtime_error("ALC version error");
108 (ALCushort
)std::min
<ALCint
>(major
, std::numeric_limits
<ALCushort
>::max()),
109 (ALCushort
)std::min
<ALCint
>(minor
, std::numeric_limits
<ALCushort
>::max())
113 ALCuint
ALDevice::getEFXVersion() const
115 if(!alcIsExtensionPresent(mDevice
, "ALC_EXT_EFX"))
118 ALCint major
=-1, minor
=-1;
119 alcGetIntegerv(mDevice
, ALC_EFX_MAJOR_VERSION
, 1, &major
);
120 alcGetIntegerv(mDevice
, ALC_EFX_MINOR_VERSION
, 1, &minor
);
121 if(major
< 0 || minor
< 0)
122 throw std::runtime_error("EFX version error");
124 (ALCushort
)std::min
<ALCint
>(major
, std::numeric_limits
<ALCushort
>::max()),
125 (ALCushort
)std::min
<ALCint
>(minor
, std::numeric_limits
<ALCushort
>::max())
129 ALCuint
ALDevice::getFrequency() const
132 alcGetIntegerv(mDevice
, ALC_FREQUENCY
, 1, &freq
);
134 throw std::runtime_error("Frequency error");
138 ALCuint
ALDevice::getMaxAuxiliarySends() const
140 if(!alcIsExtensionPresent(mDevice
, "ALC_EXT_EFX"))
144 alcGetIntegerv(mDevice
, ALC_MAX_AUXILIARY_SENDS
, 1, &sends
);
146 throw std::runtime_error("Max auxiliary sends error");
151 Vector
<String
> ALDevice::enumerateHRTFNames() const
153 if(!hasExtension(SOFT_HRTF
))
154 throw std::runtime_error("ALC_SOFT_HRTF not supported");
156 ALCint num_hrtfs
= -1;
157 alcGetIntegerv(mDevice
, ALC_NUM_HRTF_SPECIFIERS_SOFT
, 1, &num_hrtfs
);
159 throw std::runtime_error("HRTF specifier count error");
161 Vector
<String
> hrtfs
;
162 hrtfs
.reserve(num_hrtfs
);
163 for(int i
= 0;i
< num_hrtfs
;++i
)
164 hrtfs
.emplace_back(alcGetStringiSOFT(mDevice
, ALC_HRTF_SPECIFIER_SOFT
, i
));
168 bool ALDevice::isHRTFEnabled() const
170 if(!hasExtension(SOFT_HRTF
))
171 throw std::runtime_error("ALC_SOFT_HRTF not supported");
173 ALCint hrtf_state
= -1;
174 alcGetIntegerv(mDevice
, ALC_HRTF_SOFT
, 1, &hrtf_state
);
176 throw std::runtime_error("HRTF state error");
177 return hrtf_state
!= ALC_FALSE
;
180 String
ALDevice::getCurrentHRTF() const
182 if(!hasExtension(SOFT_HRTF
))
183 throw std::runtime_error("ALC_SOFT_HRTF not supported");
184 return String(alcGetString(mDevice
, ALC_HRTF_SPECIFIER_SOFT
));
187 void ALDevice::reset(ArrayView
<AttributePair
> attributes
)
189 if(!hasExtension(SOFT_HRTF
))
190 throw std::runtime_error("ALC_SOFT_HRTF not supported");
191 auto do_reset
= [this, &attributes
]() -> ALCboolean
193 if(attributes
.empty())
195 /* No explicit attributes. */
196 return alcResetDeviceSOFT(mDevice
, nullptr);
198 auto attr_end
= std::find_if(attributes
.begin(), attributes
.end(),
199 [](const AttributePair
&attr
) -> bool
200 { return std::get
<0>(attr
) == 0; }
202 if(attr_end
== attributes
.end())
204 /* Attribute list was not properly terminated. Copy the attribute
205 * list and add the 0 sentinel.
207 Vector
<AttributePair
> attrs
;
208 attrs
.reserve(attributes
.size());
209 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
210 attrs
.push_back({0, 0});
211 return alcResetDeviceSOFT(mDevice
, &std::get
<0>(attrs
.front()));
213 return alcResetDeviceSOFT(mDevice
, &std::get
<0>(attributes
.front()));
216 throw std::runtime_error("Device reset error");
220 Context
ALDevice::createContext(ArrayView
<AttributePair
> attributes
)
222 ALCcontext
*ctx
= [this, &attributes
]() -> ALCcontext
*
224 if(attributes
.empty())
226 /* No explicit attributes. */
227 return alcCreateContext(mDevice
, nullptr);
229 auto attr_end
= std::find_if(attributes
.begin(), attributes
.end(),
230 [](const AttributePair
&attr
) -> bool
231 { return std::get
<0>(attr
) == 0; }
233 if(attr_end
== attributes
.end())
235 /* Attribute list was not properly terminated. Copy the attribute
236 * list and add the 0 sentinel.
238 Vector
<AttributePair
> attrs
;
239 attrs
.reserve(attributes
.size());
240 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
241 attrs
.push_back({0, 0});
242 return alcCreateContext(mDevice
, &std::get
<0>(attrs
.front()));
244 return alcCreateContext(mDevice
, &std::get
<0>(attributes
.front()));
246 if(!ctx
) throw std::runtime_error("Failed to create context");
248 mContexts
.emplace_back(MakeUnique
<ALContext
>(ctx
, this));
249 return Context(mContexts
.back().get());
253 void ALDevice::pauseDSP()
255 if(!hasExtension(SOFT_device_pause
))
256 throw std::runtime_error("ALC_SOFT_pause_device not supported");
257 alcDevicePauseSOFT(mDevice
);
260 void ALDevice::resumeDSP()
262 if(hasExtension(SOFT_device_pause
))
263 alcDeviceResumeSOFT(mDevice
);
267 void ALDevice::close()
269 if(!mContexts
.empty())
270 throw std::runtime_error("Trying to close device with contexts");
272 if(alcCloseDevice(mDevice
) == ALC_FALSE
)
273 throw std::runtime_error("Failed to close device");
276 ALDeviceManager::get().removeDevice(this);
280 DECL_THUNK1(String
, Device
, getName
, const, PlaybackName
)
281 DECL_THUNK1(bool, Device
, queryExtension
, const, const String
&)
282 DECL_THUNK0(ALCuint
, Device
, getALCVersion
, const)
283 DECL_THUNK0(ALCuint
, Device
, getEFXVersion
, const)
284 DECL_THUNK0(ALCuint
, Device
, getFrequency
, const)
285 DECL_THUNK0(ALCuint
, Device
, getMaxAuxiliarySends
, const)
286 DECL_THUNK0(Vector
<String
>, Device
, enumerateHRTFNames
, const)
287 DECL_THUNK0(bool, Device
, isHRTFEnabled
, const)
288 DECL_THUNK0(String
, Device
, getCurrentHRTF
, const)
289 DECL_THUNK1(void, Device
, reset
,, ArrayView
<AttributePair
>)
290 DECL_THUNK1(Context
, Device
, createContext
,, ArrayView
<AttributePair
>)
291 DECL_THUNK0(void, Device
, pauseDSP
,)
292 DECL_THUNK0(void, Device
, resumeDSP
,)