11 #include "devicemanager.h"
20 static inline void LoadALCFunc(ALCdevice
*device
, T
**func
, const char *name
)
21 { *func
= reinterpret_cast<T
*>(alcGetProcAddress(device
, name
)); }
24 static void LoadPauseDevice(DeviceImpl
*device
)
26 LoadALCFunc(device
->getALCdevice(), &device
->alcDevicePauseSOFT
, "alcDevicePauseSOFT");
27 LoadALCFunc(device
->getALCdevice(), &device
->alcDeviceResumeSOFT
, "alcDeviceResumeSOFT");
30 static void LoadHrtf(DeviceImpl
*device
)
32 LoadALCFunc(device
->getALCdevice(), &device
->alcGetStringiSOFT
, "alcGetStringiSOFT");
33 LoadALCFunc(device
->getALCdevice(), &device
->alcResetDeviceSOFT
, "alcResetDeviceSOFT");
36 static void LoadNothing(DeviceImpl
*) { }
41 void (&loader
)(DeviceImpl
*);
42 } ALCExtensionList
[] = {
43 { ALC::ENUMERATE_ALL_EXT
, "ALC_ENUMERATE_ALL_EXT", LoadNothing
},
44 { ALC::EXT_EFX
, "ALC_EXT_EFX", LoadNothing
},
45 { ALC::EXT_thread_local_context
, "ALC_EXT_thread_local_context", LoadNothing
},
46 { ALC::SOFT_device_pause
, "ALC_SOFT_pause_device", LoadPauseDevice
},
47 { ALC::SOFT_HRTF
, "ALC_SOFT_HRTF", LoadHrtf
},
51 void DeviceImpl::setupExts()
54 for(const auto &entry
: ALCExtensionList
)
56 if(!alcIsExtensionPresent(mDevice
, entry
.name
))
58 mHasExt
.set(static_cast<size_t>(entry
.extension
));
64 DeviceImpl::DeviceImpl(ALCdevice
* device
)
65 : mDevice(device
), alcDevicePauseSOFT(nullptr), alcDeviceResumeSOFT(nullptr)
70 DeviceImpl::~DeviceImpl()
75 void DeviceImpl::removeContext(ContextImpl
*ctx
)
77 auto iter
= std::find_if(mContexts
.begin(), mContexts
.end(),
78 [ctx
](const UniquePtr
<ContextImpl
> &entry
) -> bool
79 { return entry
.get() == ctx
; }
81 if(iter
!= mContexts
.end()) mContexts
.erase(iter
);
85 String
DeviceImpl::getName(PlaybackName type
) const
87 if(type
== PlaybackName::Full
&& !hasExtension(ALC::ENUMERATE_ALL_EXT
))
88 type
= PlaybackName::Basic
;
90 const ALCchar
*name
= alcGetString(mDevice
, (ALenum
)type
);
91 if(alcGetError(mDevice
) != ALC_NO_ERROR
|| !name
)
92 name
= alcGetString(mDevice
, (ALenum
)PlaybackName::Basic
);
93 return name
? String(name
) : String();
96 bool DeviceImpl::queryExtension(const char *name
) const
98 return alcIsExtensionPresent(mDevice
, name
);
101 Version
DeviceImpl::getALCVersion() const
103 ALCint major
=-1, minor
=-1;
104 alcGetIntegerv(mDevice
, ALC_MAJOR_VERSION
, 1, &major
);
105 alcGetIntegerv(mDevice
, ALC_MINOR_VERSION
, 1, &minor
);
106 if(major
< 0 || minor
< 0)
107 throw std::runtime_error("ALC version error");
108 return Version
{ (ALCuint
)major
, (ALCuint
)minor
};
111 Version
DeviceImpl::getEFXVersion() const
113 if(!hasExtension(ALC::EXT_EFX
))
114 return Version
{ 0u, 0u };
116 ALCint major
=-1, minor
=-1;
117 alcGetIntegerv(mDevice
, ALC_EFX_MAJOR_VERSION
, 1, &major
);
118 alcGetIntegerv(mDevice
, ALC_EFX_MINOR_VERSION
, 1, &minor
);
119 if(major
< 0 || minor
< 0)
120 throw std::runtime_error("EFX version error");
121 return Version
{ (ALCuint
)major
, (ALCuint
)minor
};
124 ALCuint
DeviceImpl::getFrequency() const
127 alcGetIntegerv(mDevice
, ALC_FREQUENCY
, 1, &freq
);
129 throw std::runtime_error("Frequency error");
133 ALCuint
DeviceImpl::getMaxAuxiliarySends() const
135 if(!hasExtension(ALC::EXT_EFX
))
139 alcGetIntegerv(mDevice
, ALC_MAX_AUXILIARY_SENDS
, 1, &sends
);
141 throw std::runtime_error("Max auxiliary sends error");
146 Vector
<String
> DeviceImpl::enumerateHRTFNames() const
148 if(!hasExtension(ALC::SOFT_HRTF
))
149 throw std::runtime_error("ALC_SOFT_HRTF not supported");
151 ALCint num_hrtfs
= -1;
152 alcGetIntegerv(mDevice
, ALC_NUM_HRTF_SPECIFIERS_SOFT
, 1, &num_hrtfs
);
154 throw std::runtime_error("HRTF specifier count error");
156 Vector
<String
> hrtfs
;
157 hrtfs
.reserve(num_hrtfs
);
158 for(int i
= 0;i
< num_hrtfs
;++i
)
159 hrtfs
.emplace_back(alcGetStringiSOFT(mDevice
, ALC_HRTF_SPECIFIER_SOFT
, i
));
163 bool DeviceImpl::isHRTFEnabled() const
165 if(!hasExtension(ALC::SOFT_HRTF
))
166 throw std::runtime_error("ALC_SOFT_HRTF not supported");
168 ALCint hrtf_state
= -1;
169 alcGetIntegerv(mDevice
, ALC_HRTF_SOFT
, 1, &hrtf_state
);
171 throw std::runtime_error("HRTF state error");
172 return hrtf_state
!= ALC_FALSE
;
175 String
DeviceImpl::getCurrentHRTF() const
177 if(!hasExtension(ALC::SOFT_HRTF
))
178 throw std::runtime_error("ALC_SOFT_HRTF not supported");
179 return String(alcGetString(mDevice
, ALC_HRTF_SPECIFIER_SOFT
));
182 void DeviceImpl::reset(ArrayView
<AttributePair
> attributes
)
184 if(!hasExtension(ALC::SOFT_HRTF
))
185 throw std::runtime_error("ALC_SOFT_HRTF not supported");
186 auto do_reset
= [this, &attributes
]() -> ALCboolean
188 if(attributes
.empty())
190 /* No explicit attributes. */
191 return alcResetDeviceSOFT(mDevice
, nullptr);
193 auto attr_end
= std::find_if(attributes
.begin(), attributes
.end(),
194 [](const AttributePair
&attr
) -> bool
195 { return std::get
<0>(attr
) == 0; }
197 if(attr_end
== attributes
.end())
199 /* Attribute list was not properly terminated. Copy the attribute
200 * list and add the 0 sentinel.
202 Vector
<AttributePair
> attrs
;
203 attrs
.reserve(attributes
.size() + 1);
204 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
205 attrs
.push_back(AttributesEnd());
206 return alcResetDeviceSOFT(mDevice
, &std::get
<0>(attrs
.front()));
208 return alcResetDeviceSOFT(mDevice
, &std::get
<0>(attributes
.front()));
211 throw std::runtime_error("Device reset error");
215 Context
DeviceImpl::createContext(ArrayView
<AttributePair
> attributes
, bool dothrow
)
217 ALCcontext
*ctx
= [this, &attributes
]() -> ALCcontext
*
219 if(attributes
.empty())
221 /* No explicit attributes. */
222 return alcCreateContext(mDevice
, nullptr);
224 auto attr_end
= std::find_if(attributes
.begin(), attributes
.end(),
225 [](const AttributePair
&attr
) -> bool
226 { return std::get
<0>(attr
) == 0; }
228 if(attr_end
== attributes
.end())
230 /* Attribute list was not properly terminated. Copy the attribute
231 * list and add the 0 sentinel.
233 Vector
<AttributePair
> attrs
;
234 attrs
.reserve(attributes
.size() + 1);
235 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
236 attrs
.push_back(AttributesEnd());
237 return alcCreateContext(mDevice
, &std::get
<0>(attrs
.front()));
239 return alcCreateContext(mDevice
, &std::get
<0>(attributes
.front()));
244 throw std::runtime_error("Failed to create context");
248 mContexts
.emplace_back(MakeUnique
<ContextImpl
>(ctx
, this));
249 return Context(mContexts
.back().get());
253 void DeviceImpl::pauseDSP()
255 if(!hasExtension(ALC::SOFT_device_pause
))
256 throw std::runtime_error("ALC_SOFT_pause_device not supported");
257 alcDevicePauseSOFT(mDevice
);
260 void DeviceImpl::resumeDSP()
262 if(hasExtension(ALC::SOFT_device_pause
))
263 alcDeviceResumeSOFT(mDevice
);
267 void DeviceImpl::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 DeviceManagerImpl::get().removeDevice(this);
280 DECL_THUNK1(String
, Device
, getName
, const, PlaybackName
)
281 DECL_THUNK1(bool, Device
, queryExtension
, const, const char*)
282 bool Device::queryExtension(const String
&name
) const
283 { return pImpl
->queryExtension(name
.c_str()); }
284 DECL_THUNK0(Version
, Device
, getALCVersion
, const)
285 DECL_THUNK0(Version
, Device
, getEFXVersion
, const)
286 DECL_THUNK0(ALCuint
, Device
, getFrequency
, const)
287 DECL_THUNK0(ALCuint
, Device
, getMaxAuxiliarySends
, const)
288 DECL_THUNK0(Vector
<String
>, Device
, enumerateHRTFNames
, const)
289 DECL_THUNK0(bool, Device
, isHRTFEnabled
, const)
290 DECL_THUNK0(String
, Device
, getCurrentHRTF
, const)
291 DECL_THUNK1(void, Device
, reset
,, ArrayView
<AttributePair
>)
292 Context
Device::createContext(ArrayView
<AttributePair
> attrs
)
293 { return pImpl
->createContext(attrs
, true); }
294 Context
Device::createContext(ArrayView
<AttributePair
> attrs
, const std::nothrow_t
&)
295 { return pImpl
->createContext(attrs
, false); }
296 Context
Device::createContext(const std::nothrow_t
&)
297 { return pImpl
->createContext(ArrayView
<AttributePair
>(), false); }
298 DECL_THUNK0(void, Device
, pauseDSP
,)
299 DECL_THUNK0(void, Device
, resumeDSP
,)