11 #include "devicemanager.h"
18 using alure::DeviceImpl
;
23 inline void LoadALCFunc(ALCdevice
*device
, T
**func
, const char *name
)
24 { *func
= reinterpret_cast<T
*>(alcGetProcAddress(device
, name
)); }
26 void LoadPauseDevice(DeviceImpl
*device
)
28 LoadALCFunc(device
->getALCdevice(), &device
->alcDevicePauseSOFT
, "alcDevicePauseSOFT");
29 LoadALCFunc(device
->getALCdevice(), &device
->alcDeviceResumeSOFT
, "alcDeviceResumeSOFT");
32 void LoadHrtf(DeviceImpl
*device
)
34 LoadALCFunc(device
->getALCdevice(), &device
->alcGetStringiSOFT
, "alcGetStringiSOFT");
35 LoadALCFunc(device
->getALCdevice(), &device
->alcResetDeviceSOFT
, "alcResetDeviceSOFT");
38 void LoadNothing(DeviceImpl
*) { }
43 void (&loader
)(DeviceImpl
*);
44 } ALCExtensionList
[] = {
45 { ALC::ENUMERATE_ALL_EXT
, "ALC_ENUMERATE_ALL_EXT", LoadNothing
},
46 { ALC::EXT_EFX
, "ALC_EXT_EFX", LoadNothing
},
47 { ALC::EXT_thread_local_context
, "ALC_EXT_thread_local_context", LoadNothing
},
48 { ALC::SOFT_device_pause
, "ALC_SOFT_pause_device", LoadPauseDevice
},
49 { ALC::SOFT_HRTF
, "ALC_SOFT_HRTF", LoadHrtf
},
56 void DeviceImpl::setupExts()
59 for(const auto &entry
: ALCExtensionList
)
61 if(!alcIsExtensionPresent(mDevice
, entry
.name
))
63 mHasExt
.set(static_cast<size_t>(entry
.extension
));
69 DeviceImpl::DeviceImpl(const char *name
)
71 mDevice
= alcOpenDevice(name
);
72 if(!mDevice
) throw alc_error(alcGetError(nullptr), "alcOpenDevice failed");
77 DeviceImpl::~DeviceImpl()
82 alcCloseDevice(mDevice
);
87 void DeviceImpl::removeContext(ContextImpl
*ctx
)
89 auto iter
= std::find_if(mContexts
.begin(), mContexts
.end(),
90 [ctx
](const UniquePtr
<ContextImpl
> &entry
) -> bool
91 { return entry
.get() == ctx
; }
93 if(iter
!= mContexts
.end()) mContexts
.erase(iter
);
97 DECL_THUNK1(String
, Device
, getName
, const, PlaybackName
)
98 String
DeviceImpl::getName(PlaybackName type
) const
100 if(type
== PlaybackName::Full
&& !hasExtension(ALC::ENUMERATE_ALL_EXT
))
101 type
= PlaybackName::Basic
;
102 alcGetError(mDevice
);
103 const ALCchar
*name
= alcGetString(mDevice
, (ALenum
)type
);
104 if(alcGetError(mDevice
) != ALC_NO_ERROR
|| !name
)
105 name
= alcGetString(mDevice
, (ALenum
)PlaybackName::Basic
);
106 return name
? String(name
) : String();
109 bool Device::queryExtension(const String
&name
) const
110 { return pImpl
->queryExtension(name
.c_str()); }
111 DECL_THUNK1(bool, Device
, queryExtension
, const, const char*)
112 bool DeviceImpl::queryExtension(const char *name
) const
114 return static_cast<bool>(alcIsExtensionPresent(mDevice
, name
));
117 DECL_THUNK0(Version
, Device
, getALCVersion
, const)
118 Version
DeviceImpl::getALCVersion() const
120 ALCint major
=-1, minor
=-1;
121 alcGetIntegerv(mDevice
, ALC_MAJOR_VERSION
, 1, &major
);
122 alcGetIntegerv(mDevice
, ALC_MINOR_VERSION
, 1, &minor
);
123 if(major
< 0 || minor
< 0)
124 throw std::runtime_error("ALC version error");
125 return Version
{ (ALCuint
)major
, (ALCuint
)minor
};
128 DECL_THUNK0(Version
, Device
, getEFXVersion
, const)
129 Version
DeviceImpl::getEFXVersion() const
131 if(!hasExtension(ALC::EXT_EFX
))
132 return Version
{ 0u, 0u };
134 ALCint major
=-1, minor
=-1;
135 alcGetIntegerv(mDevice
, ALC_EFX_MAJOR_VERSION
, 1, &major
);
136 alcGetIntegerv(mDevice
, ALC_EFX_MINOR_VERSION
, 1, &minor
);
137 if(major
< 0 || minor
< 0)
138 throw std::runtime_error("EFX version error");
139 return Version
{ (ALCuint
)major
, (ALCuint
)minor
};
142 DECL_THUNK0(ALCuint
, Device
, getFrequency
, const)
143 ALCuint
DeviceImpl::getFrequency() const
146 alcGetIntegerv(mDevice
, ALC_FREQUENCY
, 1, &freq
);
148 throw std::runtime_error("Frequency error");
152 DECL_THUNK0(ALCuint
, Device
, getMaxAuxiliarySends
, const)
153 ALCuint
DeviceImpl::getMaxAuxiliarySends() const
155 if(!hasExtension(ALC::EXT_EFX
))
159 alcGetIntegerv(mDevice
, ALC_MAX_AUXILIARY_SENDS
, 1, &sends
);
161 throw std::runtime_error("Max auxiliary sends error");
166 DECL_THUNK0(Vector
<String
>, Device
, enumerateHRTFNames
, const)
167 Vector
<String
> DeviceImpl::enumerateHRTFNames() const
169 Vector
<String
> hrtfs
;
170 if(!hasExtension(ALC::SOFT_HRTF
))
173 ALCint num_hrtfs
= -1;
174 alcGetIntegerv(mDevice
, ALC_NUM_HRTF_SPECIFIERS_SOFT
, 1, &num_hrtfs
);
176 throw std::runtime_error("HRTF specifier count error");
178 hrtfs
.reserve(num_hrtfs
);
179 for(int i
= 0;i
< num_hrtfs
;++i
)
180 hrtfs
.emplace_back(alcGetStringiSOFT(mDevice
, ALC_HRTF_SPECIFIER_SOFT
, i
));
184 DECL_THUNK0(bool, Device
, isHRTFEnabled
, const)
185 bool DeviceImpl::isHRTFEnabled() const
187 if(!hasExtension(ALC::SOFT_HRTF
))
190 ALCint hrtf_state
= -1;
191 alcGetIntegerv(mDevice
, ALC_HRTF_SOFT
, 1, &hrtf_state
);
193 throw std::runtime_error("HRTF state error");
194 return hrtf_state
!= ALC_FALSE
;
197 DECL_THUNK0(String
, Device
, getCurrentHRTF
, const)
198 String
DeviceImpl::getCurrentHRTF() const
200 if(!hasExtension(ALC::SOFT_HRTF
))
202 return String(alcGetString(mDevice
, ALC_HRTF_SPECIFIER_SOFT
));
205 DECL_THUNK1(void, Device
, reset
,, ArrayView
<AttributePair
>)
206 void DeviceImpl::reset(ArrayView
<AttributePair
> attributes
)
208 if(!hasExtension(ALC::SOFT_HRTF
))
210 ALCboolean success
= ALC_FALSE
;
211 if(attributes
.end()) /* No explicit attributes. */
212 success
= alcResetDeviceSOFT(mDevice
, nullptr);
215 auto attr_end
= std::find_if(attributes
.rbegin(), attributes
.rend(),
216 [](const AttributePair
&attr
) -> bool
217 { return std::get
<0>(attr
) == 0; }
219 if(attr_end
== attributes
.rend())
221 /* Attribute list was not properly terminated. Copy the attribute
222 * list and add the 0 sentinel.
224 Vector
<AttributePair
> attrs
;
225 attrs
.reserve(attributes
.size() + 1);
226 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
227 attrs
.push_back(AttributesEnd());
228 success
= alcResetDeviceSOFT(mDevice
, &std::get
<0>(attrs
.front()));
231 success
= alcResetDeviceSOFT(mDevice
, &std::get
<0>(attributes
.front()));
234 throw alc_error(alcGetError(mDevice
), "alcResetDeviceSOFT failed");
238 DECL_THUNK1(Context
, Device
, createContext
,, ArrayView
<AttributePair
>)
239 Context
DeviceImpl::createContext(ArrayView
<AttributePair
> attributes
)
241 Vector
<AttributePair
> attrs
;
242 if(!attributes
.empty())
244 auto attr_end
= std::find_if(attributes
.rbegin(), attributes
.rend(),
245 [](const AttributePair
&attr
) -> bool
246 { return std::get
<0>(attr
) == 0; }
248 if(attr_end
== attributes
.rend())
250 /* Attribute list was not properly terminated. Copy the attribute
251 * list and add the 0 sentinel.
253 attrs
.reserve(attributes
.size() + 1);
254 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
255 attrs
.push_back(AttributesEnd());
260 mContexts
.emplace_back(MakeUnique
<ContextImpl
>(*this, attributes
));
261 return Context(mContexts
.back().get());
264 Context
Device::createContext(const std::nothrow_t
&) noexcept
265 { return createContext({}, std::nothrow
); }
266 Context
Device::createContext(ArrayView
<AttributePair
> attrs
, const std::nothrow_t
&) noexcept
269 return pImpl
->createContext(attrs
);
277 DECL_THUNK0(void, Device
, pauseDSP
,)
278 void DeviceImpl::pauseDSP()
280 if(!hasExtension(ALC::SOFT_device_pause
))
281 throw std::runtime_error("ALC_SOFT_pause_device not supported");
282 alcDevicePauseSOFT(mDevice
);
285 DECL_THUNK0(void, Device
, resumeDSP
,)
286 void DeviceImpl::resumeDSP()
288 if(hasExtension(ALC::SOFT_device_pause
))
289 alcDeviceResumeSOFT(mDevice
);
295 DeviceImpl
*i
= pImpl
;
299 void DeviceImpl::close()
301 if(!mContexts
.empty())
302 throw std::runtime_error("Trying to close device with contexts");
304 if(alcCloseDevice(mDevice
) == ALC_FALSE
)
305 throw alc_error(alcGetError(mDevice
), "alcCloseDevice failed");
308 DeviceManagerImpl::getInstance()->removeDevice(this);