Crash On Linux doing a: new OgreAL::SoundManager();

libolt

30-11-2007 06:24:12

Hi,

I'm attempting to integrate OgreAL into my project for sound playback. I tried following the Basic Demo to get an idea of how to set everything up.

However it crashes on:


soundMgr = OgreAL::SoundManager::getSingletonPtr();


I have created as simple of a test app as I can to reproduce this problem:


#include "input.h"
#include "simulation.h"

#include "Ogre.h"

#include "OgreWindowEventUtilities.h"

#include "OgreAL.h"

#if defined(WIN32)
#include "windows.h"

using namespace Ogre;

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
#else
int main (int argc, char *argv[]) {
#endif

Ogre::Root *ogre;
Ogre::RenderWindow *window;
Ogre::SceneManager *sceneMgr;
Ogre::Camera *camera;
// fire up an Ogre rendering window. Clearing the first two (of three) params will let us
// specify plugins and resources in code instead of via text file
ogre = new Ogre::Root("", "");


#if defined(_DEBUG)
ogre->loadPlugin("RenderSystem_GL_d");
#else
ogre->loadPlugin("/usr/local/lib/OGRE/RenderSystem_GL");
#endif

Ogre::RenderSystemList *renderSystems = NULL;
Ogre::RenderSystemList::iterator r_it;

// we do this step just to get an iterator that we can use with setRenderSystem. In a future article
// we actually will iterate the list to display which renderers are available.
renderSystems = ogre->getAvailableRenderers();
r_it = renderSystems->begin();
ogre->setRenderSystem(*r_it);
ogre->initialise(false);

// load common plugins
#if defined(_DEBUG)
ogre->loadPlugin("Plugin_CgProgramManager_d");
ogre->loadPlugin("Plugin_OctreeSceneManager_d");
#else
ogre->loadPlugin("/usr/local/lib/OGRE/Plugin_CgProgramManager");
ogre->loadPlugin("/usr/local/lib/OGRE/Plugin_ParticleFX");
// ogre->loadPlugin("Plugin_OctreeSceneManager");
#endif

// load the basic resource location(s)
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"resource", "FileSystem", "General");
Ogre::ResourceGroupManager::getSingleton().addResourceLocation("Audio", "FileSystem", "General");


#if defined(WIN32)
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
"c:\\windows\\fonts", "FileSystem", "GUI");
#endif

Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("General");
// Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("GUI");
// setup main window; hardcode some defaults for the sake of presentation
Ogre::NameValuePairList opts;
opts["resolution"] = "1024x768";
opts["fullscreen"] = "false";
opts["vsync"] = "false";

// create a rendering window with the title "CDK"
window = ogre->createRenderWindow("OgreAL Test", 1024, 768, false, &opts);

// since this is basically a CEGUI app, we can use the ST_GENERIC scene manager for now; in a later article
// we'll see how to change this
sceneMgr = ogre->createSceneManager(Ogre::ST_GENERIC);
camera = sceneMgr->createCamera("camera");
// Position it at 500 in Z direction
camera->setPosition(Ogre::Vector3(0,0,500));
// Look back along -Z
camera->lookAt(Ogre::Vector3(0,0,-300));

camera->setNearClipDistance(5);
Ogre::Viewport* vp = window->addViewport(camera);
vp->setBackgroundColour(Ogre::ColourValue(0,0,0));

// most examples get the viewport size to calculate this; for now, we'll just
// set it to 4:3 the easy way
camera->setAspectRatio((Ogre::Real)1.333333);

OgreAL::SoundManager *soundMgr;
soundMgr = new OgreAL::SoundManager();
// OgreAL::Sound *snd;
// snd = OgreAL::SoundManager::getSingletonPtr()->createSound("dead", "roar.wav", false);

// this next bit is for the sake of the input handler
unsigned long hWnd;
window->getCustomAttribute("WINDOW", &hWnd);

sceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5));
Ogre::Light* l = sceneMgr->createLight("MainLight");
l->setPosition(20,80,56);
bool QUIT;
QUIT = false;
while (!QUIT)
{

// handler->capture();

// run the message pump (Eihort)
Ogre::WindowEventUtilities::messagePump();

ogre->renderOneFrame();
}

// clean up after ourselves
delete ogre;

return 0;
}



Now this dies with the following:


*-*-* OgreAL Initialization
MovableObjectFactory for type 'OgreAL_Sound' registered.
MovableObjectFactory for type 'OgreAL_Listener' registered.
*-*-* Creating OpenAL
OpenAL Devices
--------------
OGRE EXCEPTION(40961:): Failed to open Device: OpenAL Error: The specified source name is not valid in initializeDevice
terminate called after throwing an instance of 'Ogre::Exception'
what(): OGRE EXCEPTION(40961:): Failed to open Device: OpenAL Error: The specified source name is not valid in initializeDevice

Program received signal SIGABRT, Aborted.



I get the following backtrace out of GDB:


(gdb) bt
#0 0x00002ba32ad57765 in raise () from /lib/libc.so.6
#1 0x00002ba32ad591c0 in abort () from /lib/libc.so.6
#2 0x00002ba32a6517b4 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib/libstdc++.so.6
#3 0x00002ba32a64f746 in ?? () from /usr/lib/libstdc++.so.6
#4 0x00002ba32a64f773 in std::terminate () from /usr/lib/libstdc++.so.6
#5 0x00002ba32a64f85a in __cxa_throw () from /usr/lib/libstdc++.so.6
#6 0x00002ba329727305 in OgreAL::check (error=40961, description=<value optimized out>, source=@0x7fff8216b310)
at OgreALException.cpp:59
#7 0x00002ba32971ba35 in OgreAL::SoundManager::initializeDevice (this=0x1107660, deviceName=@0x7fff8216b700)
at OgreALSoundManager.cpp:385
#8 0x00002ba32971cde4 in SoundManager (this=0x1107660, deviceName=@0x7fff8216b700) at OgreALSoundManager.cpp:70
#9 0x000000000040457f in main (argc=1, argv=0x7fff8216b878) at /home/libolt/Projects/ogretest/main.cpp:124


Is there perhaps something I'm missing or doing wrong? Any help is greatly appreciated.

Mike

CaseyB

30-11-2007 06:42:45

It's actually dying when it tries to open your audio hardware in the SoundManager::initializeDevice() method. What's supposed to happen in that method is that it checks to see if the device name that you pass in matches any of the available devices and if it does then it uses that device. If you pass in an invalid name or no name at all it opens up the default device. Can you post the part of your Ogre.log that shows the initialization of OgreAL? That should show which devices it found. Did you remember to install the OpenAL redistributable package?

libolt

30-11-2007 07:01:14

This is all I have for OgreAL in my Ogre.log:


23:32:55: *-*-* OgreAL Initialization
23:32:55: MovableObjectFactory for type 'OgreAL_Sound' registered.
23:32:55: MovableObjectFactory for type 'OgreAL_Listener' registered.
23:32:55: *-*-* Creating OpenAL
23:32:55: OpenAL Devices
23:32:55: --------------
23:32:55: OGRE EXCEPTION(40961:): Failed to open Device: OpenAL Error: The specified source name is not valid in initializeDevice



This is all on an AMD64 Linux install. I have an SB Audigy 2 with builtin hardware mixer. I have run other OpenAL applications without issue such as FlightGear.

I'm running the latest subversion of OgreAL.

CaseyB

30-11-2007 07:23:15

Yeah, for some reason it's not finding any devices when I query the hardware. Here's what my log looks like.06:19:52: *-*-* OgreAL Initialization
06:19:52: MovableObjectFactory for type 'OgreAL_Sound' registered.
06:19:52: MovableObjectFactory for type 'OgreAL_Listener' registered.
06:19:52: *-*-* Creating OpenAL
06:19:52: OpenAL Devices
06:19:52: --------------
06:19:52: * Generic Hardware
06:19:52: * Generic Software
06:19:53: Choosing: Generic Hardware
I am not sure why it's not finding any. I'll look into it.

CaseyB

30-11-2007 07:51:45

Ok, you mentioned FlightGear was working so I looked into that and they use an engine called SimGear. I looked into the SimGear source and here is what I found.#if defined(ALUT_API_MAJOR_VERSION) && ALUT_API_MAJOR_VERSION >= 1
if (!alutInit(NULL, NULL))
{
ALenum error = alutGetError ();
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
SG_LOG( SG_GENERAL, SG_ALERT, " "+string(alutGetErrorString(error)));
working = false;
context = 0;
}
else
{
working = true;
context = alcGetCurrentContext();
}
#else
if ( (dev = alcOpenDevice( NULL )) != NULL
&& ( context = alcCreateContext( dev, NULL )) != NULL ) {
working = true;
alcMakeContextCurrent( context );
} else {
working = false;
context = 0;
SG_LOG( SG_GENERAL, SG_ALERT, "Audio initialization failed!" );
}
#endif
So it could be using alut or not depending on how you have your system set up. If not then they are doing pretty much the same thing I am, just less flexibly. Here's what I've got: void SoundManager::initializeDevice(const Ogre::String& deviceName)
{
Ogre::LogManager::getSingleton().logMessage("OpenAL Devices");
Ogre::LogManager::getSingleton().logMessage("--------------");

std::stringstream ss;

// List devices in log and see if the sugested device is in the list
Ogre::StringVector deviceList = getDeviceList();
bool deviceInList = false;
Ogre::StringVector::iterator deviceItr;
for(deviceItr = deviceList.begin(); deviceItr != deviceList.end(); deviceItr++)
{
deviceInList = (*deviceItr).compare(deviceName) == 0;
ss << " * " << (*deviceItr);
Ogre::LogManager::getSingleton().logMessage(ss.str());
ss.clear(); ss.str("");
}

// If the suggested device is in the list we use it, otherwise select the default device
mDevice = alcOpenDevice(deviceInList ? deviceName.c_str() : NULL);
CheckError(alcGetError(mDevice), "Failed to open Device");
CheckCondition(mDevice != NULL, 13, "Failed to open audio device");

Ogre::LogManager::getSingleton().logMessage("Choosing: " + Ogre::String(alcGetString(mDevice, ALC_DEVICE_SPECIFIER)));

// Create OpenAL Context
mContext = alcCreateContext(mDevice, NULL);
CheckError(alcGetError(mDevice), "Failed to create Context");
CheckCondition(mContext != NULL, 13, "Failed to create OpenAL Context");

alcMakeContextCurrent(mContext);
CheckError(alcGetError(mDevice), "Failed to set current context");
}
So it should default to NULL if the deviceName is invalid. Here's a patch that beefs up error checking in the getDeviceList() method, maybe the problem is there.Index: src/OgreALSoundManager.cpp
===================================================================
--- src/OgreALSoundManager.cpp (revision 88)
+++ src/OgreALSoundManager.cpp (working copy)
@@ -249,6 +249,7 @@
Ogre::StringVector SoundManager::getDeviceList()
{
const ALCchar* deviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
+ CheckError(alGetError(), "Unable to list devices");

Ogre::StringVector deviceVector;
/*
@@ -264,16 +265,20 @@
while(*deviceList != NULL)
{
ALCdevice *device = alcOpenDevice(deviceList);
+ CheckError(alGetError(), "Unable to open device");
if(device)
{
// Device seems to be valid
ALCcontext *context = alcCreateContext(device, NULL);
+ CheckError(alGetError(), "Unable to create context");
if(context)
{
// Context seems to be valid
alcMakeContextCurrent(context);
+ CheckError(alGetError(), "Unable to make context current");
deviceVector.push_back(alcGetString(device, ALC_DEVICE_SPECIFIER));
alcDestroyContext(context);
+ CheckError(alGetError(), "Unable to destroy context");
}
alcCloseDevice(device);
}
@@ -362,8 +376,6 @@

void SoundManager::initializeDevice(const Ogre::String& deviceName)
{
- bool deviceInList = false;
-
Ogre::LogManager::getSingleton().logMessage("OpenAL Devices");
Ogre::LogManager::getSingleton().logMessage("--------------");

@@ -371,6 +383,7 @@

// List devices in log and see if the sugested device is in the list
Ogre::StringVector deviceList = getDeviceList();
+ bool deviceInList = false;
Ogre::StringVector::iterator deviceItr;
for(deviceItr = deviceList.begin(); deviceItr != deviceList.end(); deviceItr++)
{
This patch will be in SVN soon, but I am in the middle of changing things around so it's not ready to commit yet.

dermont

26-07-2008 13:13:13

Shouldn't the comparison with the deviceName and deviceList be only be carried out if a deviceName hasn't been found. Otherwise the default device is always selected unless the deviceName is the last item in the deviceList.


Index: OgreALSoundManager.cpp
===================================================================
--- OgreALSoundManager.cpp (revision 115)
+++ OgreALSoundManager.cpp (working copy)
@@ -704,8 +704,9 @@
std::stringstream ss;

Ogre::StringVector::iterator deviceItr;

for(deviceItr = deviceList.begin(); deviceItr != deviceList.end() && (*deviceItr).compare("") != 0; deviceItr++)

- {

- deviceInList = (*deviceItr).compare(deviceName) == 0;

+ {
+ if (!deviceInList)

+ deviceInList = (*deviceItr).compare(deviceName) == 0;

ss << " * " << (*deviceItr);

Ogre::LogManager::getSingleton().logMessage(ss.str());

ss.clear(); ss.str("");

stickymango

29-07-2008 09:14:32

Actually the comparison should look like this: for(deviceItr = deviceList.begin(); deviceItr != deviceList.end() && (*deviceItr).compare("") != 0; deviceItr++)
{
deviceInList |= (*deviceItr).compare(deviceName) == 0;
ss << " * " << (*deviceItr);
Ogre::LogManager::getSingleton().logMessage(ss.str());
ss.clear(); ss.str("");
}

dermont

02-08-2008 09:21:41

Ok, thanks for the feedback. After posting I realized there were more elegant ways to implement the code above.