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(DeviceImpl
*device
)
29 LoadALCFunc(device
->getDevice(), &device
->alcDevicePauseSOFT
, "alcDevicePauseSOFT");
30 LoadALCFunc(device
->getDevice(), &device
->alcDeviceResumeSOFT
, "alcDeviceResumeSOFT");
33 static void LoadHrtf(DeviceImpl
*device
)
35 LoadALCFunc(device
->getDevice(), &device
->alcGetStringiSOFT
, "alcGetStringiSOFT");
36 LoadALCFunc(device
->getDevice(), &device
->alcResetDeviceSOFT
, "alcResetDeviceSOFT");
39 static void LoadNothing(DeviceImpl
*) { }
42 enum ALCExtension extension
;
44 void (&loader
)(DeviceImpl
*);
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 DeviceImpl::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 DeviceImpl::DeviceImpl(ALCdevice
* device
)
64 : mDevice(device
), alcDevicePauseSOFT(nullptr), alcDeviceResumeSOFT(nullptr)
69 DeviceImpl::~DeviceImpl()
74 void DeviceImpl::removeContext(ContextImpl
*ctx
)
76 auto iter
= std::find_if(mContexts
.begin(), mContexts
.end(),
77 [ctx
](const UniquePtr
<ContextImpl
> &entry
) -> bool
78 { return entry
.get() == ctx
; }
80 if(iter
!= mContexts
.end()) mContexts
.erase(iter
);
84 String
DeviceImpl::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 DeviceImpl::queryExtension(const char *name
) const
97 return alcIsExtensionPresent(mDevice
, name
);
100 Version
DeviceImpl::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");
107 return Version
{ (ALCuint
)major
, (ALCuint
)minor
};
110 Version
DeviceImpl::getEFXVersion() const
112 if(!alcIsExtensionPresent(mDevice
, "ALC_EXT_EFX"))
113 return Version
{ 0u, 0u };
115 ALCint major
=-1, minor
=-1;
116 alcGetIntegerv(mDevice
, ALC_EFX_MAJOR_VERSION
, 1, &major
);
117 alcGetIntegerv(mDevice
, ALC_EFX_MINOR_VERSION
, 1, &minor
);
118 if(major
< 0 || minor
< 0)
119 throw std::runtime_error("EFX version error");
120 return Version
{ (ALCuint
)major
, (ALCuint
)minor
};
123 ALCuint
DeviceImpl::getFrequency() const
126 alcGetIntegerv(mDevice
, ALC_FREQUENCY
, 1, &freq
);
128 throw std::runtime_error("Frequency error");
132 ALCuint
DeviceImpl::getMaxAuxiliarySends() const
134 if(!alcIsExtensionPresent(mDevice
, "ALC_EXT_EFX"))
138 alcGetIntegerv(mDevice
, ALC_MAX_AUXILIARY_SENDS
, 1, &sends
);
140 throw std::runtime_error("Max auxiliary sends error");
145 Vector
<String
> DeviceImpl::enumerateHRTFNames() const
147 if(!hasExtension(SOFT_HRTF
))
148 throw std::runtime_error("ALC_SOFT_HRTF not supported");
150 ALCint num_hrtfs
= -1;
151 alcGetIntegerv(mDevice
, ALC_NUM_HRTF_SPECIFIERS_SOFT
, 1, &num_hrtfs
);
153 throw std::runtime_error("HRTF specifier count error");
155 Vector
<String
> hrtfs
;
156 hrtfs
.reserve(num_hrtfs
);
157 for(int i
= 0;i
< num_hrtfs
;++i
)
158 hrtfs
.emplace_back(alcGetStringiSOFT(mDevice
, ALC_HRTF_SPECIFIER_SOFT
, i
));
162 bool DeviceImpl::isHRTFEnabled() const
164 if(!hasExtension(SOFT_HRTF
))
165 throw std::runtime_error("ALC_SOFT_HRTF not supported");
167 ALCint hrtf_state
= -1;
168 alcGetIntegerv(mDevice
, ALC_HRTF_SOFT
, 1, &hrtf_state
);
170 throw std::runtime_error("HRTF state error");
171 return hrtf_state
!= ALC_FALSE
;
174 String
DeviceImpl::getCurrentHRTF() const
176 if(!hasExtension(SOFT_HRTF
))
177 throw std::runtime_error("ALC_SOFT_HRTF not supported");
178 return String(alcGetString(mDevice
, ALC_HRTF_SPECIFIER_SOFT
));
181 void DeviceImpl::reset(ArrayView
<AttributePair
> attributes
)
183 if(!hasExtension(SOFT_HRTF
))
184 throw std::runtime_error("ALC_SOFT_HRTF not supported");
185 auto do_reset
= [this, &attributes
]() -> ALCboolean
187 if(attributes
.empty())
189 /* No explicit attributes. */
190 return alcResetDeviceSOFT(mDevice
, nullptr);
192 auto attr_end
= std::find_if(attributes
.begin(), attributes
.end(),
193 [](const AttributePair
&attr
) -> bool
194 { return std::get
<0>(attr
) == 0; }
196 if(attr_end
== attributes
.end())
198 /* Attribute list was not properly terminated. Copy the attribute
199 * list and add the 0 sentinel.
201 Vector
<AttributePair
> attrs
;
202 attrs
.reserve(attributes
.size() + 1);
203 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
204 attrs
.push_back(AttributesEnd
);
205 return alcResetDeviceSOFT(mDevice
, &std::get
<0>(attrs
.front()));
207 return alcResetDeviceSOFT(mDevice
, &std::get
<0>(attributes
.front()));
210 throw std::runtime_error("Device reset error");
214 Context
DeviceImpl::createContext(ArrayView
<AttributePair
> attributes
, bool dothrow
)
216 ALCcontext
*ctx
= [this, &attributes
]() -> ALCcontext
*
218 if(attributes
.empty())
220 /* No explicit attributes. */
221 return alcCreateContext(mDevice
, nullptr);
223 auto attr_end
= std::find_if(attributes
.begin(), attributes
.end(),
224 [](const AttributePair
&attr
) -> bool
225 { return std::get
<0>(attr
) == 0; }
227 if(attr_end
== attributes
.end())
229 /* Attribute list was not properly terminated. Copy the attribute
230 * list and add the 0 sentinel.
232 Vector
<AttributePair
> attrs
;
233 attrs
.reserve(attributes
.size() + 1);
234 std::copy(attributes
.begin(), attributes
.end(), std::back_inserter(attrs
));
235 attrs
.push_back(AttributesEnd
);
236 return alcCreateContext(mDevice
, &std::get
<0>(attrs
.front()));
238 return alcCreateContext(mDevice
, &std::get
<0>(attributes
.front()));
243 throw std::runtime_error("Failed to create context");
247 mContexts
.emplace_back(MakeUnique
<ContextImpl
>(ctx
, this));
248 return Context(mContexts
.back().get());
252 void DeviceImpl::pauseDSP()
254 if(!hasExtension(SOFT_device_pause
))
255 throw std::runtime_error("ALC_SOFT_pause_device not supported");
256 alcDevicePauseSOFT(mDevice
);
259 void DeviceImpl::resumeDSP()
261 if(hasExtension(SOFT_device_pause
))
262 alcDeviceResumeSOFT(mDevice
);
266 void DeviceImpl::close()
268 if(!mContexts
.empty())
269 throw std::runtime_error("Trying to close device with contexts");
271 if(alcCloseDevice(mDevice
) == ALC_FALSE
)
272 throw std::runtime_error("Failed to close device");
275 DeviceManagerImpl::get().removeDevice(this);
279 DECL_THUNK1(String
, Device
, getName
, const, PlaybackName
)
280 DECL_THUNK1(bool, Device
, queryExtension
, const, const char*)
281 bool Device::queryExtension(const String
&name
) const
282 { return pImpl
->queryExtension(name
.c_str()); }
283 DECL_THUNK0(Version
, Device
, getALCVersion
, const)
284 DECL_THUNK0(Version
, Device
, getEFXVersion
, const)
285 DECL_THUNK0(ALCuint
, Device
, getFrequency
, const)
286 DECL_THUNK0(ALCuint
, Device
, getMaxAuxiliarySends
, const)
287 DECL_THUNK0(Vector
<String
>, Device
, enumerateHRTFNames
, const)
288 DECL_THUNK0(bool, Device
, isHRTFEnabled
, const)
289 DECL_THUNK0(String
, Device
, getCurrentHRTF
, const)
290 DECL_THUNK1(void, Device
, reset
,, ArrayView
<AttributePair
>)
291 Context
Device::createContext(ArrayView
<AttributePair
> attrs
)
292 { return pImpl
->createContext(attrs
, true); }
293 Context
Device::createContext(ArrayView
<AttributePair
> attrs
, const std::nothrow_t
&)
294 { return pImpl
->createContext(attrs
, false); }
295 Context
Device::createContext(const std::nothrow_t
&)
296 { return pImpl
->createContext(ArrayView
<AttributePair
>(), false); }
297 DECL_THUNK0(void, Device
, pauseDSP
,)
298 DECL_THUNK0(void, Device
, resumeDSP
,)