Browse Source

Audio: ability to defer context creation to a later time.

pull/255/head
Vladimír Vondruš 8 years ago
parent
commit
703a664fd2
  1. 116
      src/Magnum/Audio/Context.cpp
  2. 32
      src/Magnum/Audio/Context.h
  3. 10
      src/Magnum/Audio/Test/ContextTest.cpp

116
src/Magnum/Audio/Context.cpp

@ -117,19 +117,73 @@ Context& Context::current() {
Context::Context(): Context{Configuration{}} {}
#endif
Context::Context(const Configuration& config) {
CORRADE_ASSERT(!_current, "Audio::Context: context already created", );
Context::Context(const Configuration& configuration) {
create(configuration);
}
Context::Context(NoCreateT) noexcept: _device{}, _context{} {}
void Context::create(const Configuration& configuration) {
if(!tryCreate(configuration)) std::exit(1);
}
bool Context::tryCreate(const Configuration& configuration) {
CORRADE_ASSERT(!_current, "Audio::Context: context already created", false);
/* Open the device */
const ALCchar* const deviceSpecifier = config.deviceSpecifier().empty() ? alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER) : config.deviceSpecifier().data();
const ALCchar* const deviceSpecifier = configuration.deviceSpecifier().empty() ? alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER) : configuration.deviceSpecifier().data();
if(!(_device = alcOpenDevice(deviceSpecifier))) {
Error() << "Audio::Context: cannot open sound device" << deviceSpecifier;
std::exit(1);
return false;
}
/* The following parameters are order dependent!
Make sure to always add sufficient space at end of the attributes
array.*/
Int attributes[]{
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0 /* sentinel */
};
/* last valid index in the attributes array */
Int last = 0;
if(configuration.frequency() != -1) {
attributes[last++] = ALC_FREQUENCY;
attributes[last++] = configuration.frequency();
}
if(configuration.hrtf() != Configuration::Hrtf::Default) {
attributes[last++] = ALC_HRTF_SOFT;
attributes[last++] = (configuration.hrtf() == Configuration::Hrtf::Enabled)
? ALC_TRUE : ALC_FALSE;
}
if(configuration.monoSourceCount() != -1) {
attributes[last++] = ALC_MONO_SOURCES;
attributes[last++] = configuration.monoSourceCount();
}
if(configuration.stereoSourceCount() != -1) {
attributes[last++] = ALC_STEREO_SOURCES;
attributes[last++] = configuration.stereoSourceCount();
}
if(configuration.refreshRate() != -1) {
attributes[last++] = ALC_REFRESH;
attributes[last++] = configuration.refreshRate();
}
if(!tryCreateContext(config)) {
#ifndef CORRADE_TARGET_EMSCRIPTEN
_context = alcCreateContext(_device, attributes);
#else
if(last != 0)
Warning() << "Audio::Context::tryCreateContext(): specifying attributes is not supported with Emscripten, ignoring";
_context = alcCreateContext(_device, nullptr);
#endif
if(!_context) {
Error() << "Audio::Context: cannot create context:" << alcErrorString(alcGetError(_device));
std::exit(1);
return false;
}
alcMakeContextCurrent(_context);
@ -153,6 +207,8 @@ Context::Context(const Configuration& config) {
/* Print some info */
Debug() << "Audio Renderer:" << rendererString() << "by" << vendorString();
Debug() << "OpenAL version:" << versionString();
return true;
}
Context::Context(Context&& other) noexcept: _device{other._device}, _context{other._context}, _extensionStatus{std::move(other._extensionStatus)}, _supportedExtensions{std::move(other._supportedExtensions)} {
@ -220,54 +276,6 @@ std::string Context::versionString() const {
return alGetString(AL_VERSION);
}
bool Context::tryCreateContext(const Configuration& config) {
/* The following parameters are order dependent!
Make sure to always add sufficient space at end of the attributes
array.*/
Int attributes[]{
0, 0,
0, 0,
0, 0,
0, 0,
0, 0,
0 /* sentinel */
};
/* last valid index in the attributes array */
Int last = 0;
if(config.frequency() != -1) {
attributes[last++] = ALC_FREQUENCY;
attributes[last++] = config.frequency();
}
if(config.hrtf() != Configuration::Hrtf::Default) {
attributes[last++] = ALC_HRTF_SOFT;
attributes[last++] = (config.hrtf() == Configuration::Hrtf::Enabled)
? ALC_TRUE : ALC_FALSE;
}
if(config.monoSourceCount() != -1) {
attributes[last++] = ALC_MONO_SOURCES;
attributes[last++] = config.monoSourceCount();
}
if(config.stereoSourceCount() != -1) {
attributes[last++] = ALC_STEREO_SOURCES;
attributes[last++] = config.stereoSourceCount();
}
if(config.refreshRate() != -1) {
attributes[last++] = ALC_REFRESH;
attributes[last++] = config.refreshRate();
}
#ifndef CORRADE_TARGET_EMSCRIPTEN
_context = alcCreateContext(_device, attributes);
#else
if(last != 0)
Warning() << "Audio::Context::tryCreateContext(): specifying attributes is not supported with Emscripten, ignoring";
_context = alcCreateContext(_device, nullptr);
#endif
return !!_context;
}
Context::Configuration::Configuration() = default;
Context::Configuration::~Configuration() = default;

32
src/Magnum/Audio/Context.h

@ -39,6 +39,7 @@
#include <Corrade/Utility/Debug.h>
#include "Magnum/Magnum.h"
#include "Magnum/Tags.h"
#include "Magnum/Audio/visibility.h"
#include "MagnumExternal/OpenAL/extensions.h"
@ -163,6 +164,15 @@ class MAGNUM_AUDIO_EXPORT Context {
explicit Context();
#endif
/**
* @brief Construct without creating the underlying OpenAL context
*
* Useful in cases where you need to defer context creation to a later
* time, for example to do a more involved configuration. Call
* @ref create() or @ref tryCreate() to create the actual context.
*/
explicit Context(NoCreateT) noexcept;
/** @brief Copying is not allowed */
Context(const Context&) = delete;
@ -187,6 +197,24 @@ class MAGNUM_AUDIO_EXPORT Context {
CORRADE_DEPRECATED("Audio::Context::current() returns reference now") operator Context*() { return this; }
#endif
/**
* @brief Complete the context setup and exit on failure
*
* Finalizes the setup after the class was created using
* @ref Context(NoCreateT). If any error occurs, a message is printed
* to error output and the application exits. See @ref tryCreate() for
* an alternative.
*/
void create(const Configuration& configuration);
/**
* @brief Complete the context setup
*
* Unlike @ref create() just prints a message to error output and
* returns `false` on error.
*/
bool tryCreate(const Configuration& configuration);
/**
* @brief Whether HRTFs (Head Related Transfer Functions) are enabled
*
@ -318,10 +346,6 @@ class MAGNUM_AUDIO_EXPORT Context {
private:
MAGNUM_AUDIO_LOCAL static Context* _current;
/* Create a context with given configuration. Returns `true` on success.
* @ref alcCreateContext(). */
MAGNUM_AUDIO_LOCAL bool tryCreateContext(const Configuration& config);
ALCdevice* _device;
ALCcontext* _context;

10
src/Magnum/Audio/Test/ContextTest.cpp

@ -34,6 +34,7 @@ namespace Magnum { namespace Audio { namespace Test {
struct ContextTest: TestSuite::Tester {
explicit ContextTest();
void constructNoCreate();
void constructCopyMove();
void extensions();
@ -42,13 +43,20 @@ struct ContextTest: TestSuite::Tester {
};
ContextTest::ContextTest() {
addTests({&ContextTest::constructCopyMove,
addTests({&ContextTest::constructNoCreate,
&ContextTest::constructCopyMove,
&ContextTest::extensions,
&ContextTest::debugHrtfStatus});
}
void ContextTest::constructNoCreate() {
Context context{NoCreate};
CORRADE_VERIFY(!Context::hasCurrent());
}
void ContextTest::constructCopyMove() {
/* Only move-construction allowed */
CORRADE_VERIFY(!(std::is_constructible<Context, const Context&>{}));

Loading…
Cancel
Save