diff --git a/panda/src/audiotraits/config_openalAudio.cxx b/panda/src/audiotraits/config_openalAudio.cxx index ab89ad775f..fe8cc6e128 100644 --- a/panda/src/audiotraits/config_openalAudio.cxx +++ b/panda/src/audiotraits/config_openalAudio.cxx @@ -27,6 +27,12 @@ ConfigureFn(config_openalAudio) { init_libOpenALAudio(); } +ConfigVariableString openal_device +("openal-device", "", + PRC_DESC("Specify the OpenAL device string for audio playback (no quotes). If this " + "is not specified, the OpenAL default device is used.")); + + //////////////////////////////////////////////////////////////////// // Function: init_libOpenALAudio // Description: Initializes the library. This must be called at diff --git a/panda/src/audiotraits/config_openalAudio.h b/panda/src/audiotraits/config_openalAudio.h index 9a122e2d90..646e13bdc8 100644 --- a/panda/src/audiotraits/config_openalAudio.h +++ b/panda/src/audiotraits/config_openalAudio.h @@ -27,4 +27,6 @@ NotifyCategoryDecl(openalAudio, EXPCL_OPENAL_AUDIO, EXPTP_OPENAL_AUDIO); extern EXPCL_OPENAL_AUDIO void init_libOpenALAudio(); extern "C" EXPCL_OPENAL_AUDIO Create_AudioManager_proc *get_audio_manager_func_openal_audio(); +extern ConfigVariableString openal_device; + #endif // CONFIG_OPENALAUDIO_H diff --git a/panda/src/audiotraits/openalAudioManager.cxx b/panda/src/audiotraits/openalAudioManager.cxx index 0a8faa896d..814ef7c69e 100644 --- a/panda/src/audiotraits/openalAudioManager.cxx +++ b/panda/src/audiotraits/openalAudioManager.cxx @@ -19,6 +19,7 @@ #include "config_audio.h" #include "config_util.h" #include "config_express.h" +#include "config_openalAudio.h" #include "openalAudioManager.h" #include "openalAudioSound.h" #include "virtualFileSystem.h" @@ -117,10 +118,11 @@ OpenALAudioManager() { // Initialization if (_active_managers == 0 || !_openal_active) { - _device = alcOpenDevice(NULL); // select the "preferred device" + string dev_name = get_audio_device(); + _device = alcOpenDevice(dev_name.empty() ? NULL : dev_name.c_str()); // select the user or preferred device if (!_device) { // this is a unique kind of error - audio_error("OpenALAudioManager: alcOpenDevice(NULL): ALC couldn't open device"); + audio_cat->error() << "OpenALAudioManager: alcOpenDevice(\"" << dev_name << "\"): ALC couldn't open device" << endl; } else { alcGetError(_device); // clear errors _context = alcCreateContext(_device, NULL); @@ -212,6 +214,65 @@ is_valid() { return _is_valid; } +//////////////////////////////////////////////////////////////////// +// Function: OpenALAudioManager::get_device_list +// Access: Private +// Description: Interrogate the system for audio devices. +//////////////////////////////////////////////////////////////////// +std::vector OpenALAudioManager:: +get_device_list() { + std::vector devList; + const char* deviceList = 0; + + if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE) { + audio_cat->debug() << "Using ALC_ENUMERATE_ALL_EXT" << endl; + deviceList = (const char*) alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + } else if (alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT") == AL_TRUE) { + audio_cat->debug() << "Using ALC_ENUMERATION_EXT" << endl; + deviceList = (const char*) alcGetString(NULL, ALC_DEVICE_SPECIFIER); + } + + if (deviceList) { + while (*deviceList) { + string dev = deviceList; + devList.push_back(dev); + audio_cat->debug() << " " << dev << endl; + deviceList += strlen(deviceList) + 1; + } + } + return devList; +} + +//////////////////////////////////////////////////////////////////// +// Function: OpenALAudioManager::get_audio_device +// Access: Private +// Description: Fetch the audio device matching one in the +// configuration, or bail and return blank. +//////////////////////////////////////////////////////////////////// +std::string OpenALAudioManager:: +get_audio_device() { + std::vector devList = get_device_list(); + if (devList.empty()) { + audio_cat->warning() << "No devices enumerated by OpenAL; using default" << endl; + return ""; + } + + std::string device = openal_device; + if (!device.empty()) { + if (std::find(devList.begin(), devList.end(), device) == devList.end()) { + audio_cat->warning() << "Requested OpenAL device " << device << " not detected; using default." << endl; + return ""; + } + + audio_cat->info() << "Using OpenAL device " << device << endl; + return device; + } + + // default + audio_cat->info() << "Using default OpenAL device" << endl; + return ""; +} + //////////////////////////////////////////////////////////////////// // Function: OpenALAudioManager::make_current // Access: Private diff --git a/panda/src/audiotraits/openalAudioManager.h b/panda/src/audiotraits/openalAudioManager.h index 0dcc0e07e2..66b7ecedd1 100644 --- a/panda/src/audiotraits/openalAudioManager.h +++ b/panda/src/audiotraits/openalAudioManager.h @@ -116,6 +116,9 @@ class EXPCL_OPENAL_AUDIO OpenALAudioManager : public AudioManager { virtual void update(); private: + std::vector get_device_list(); + std::string get_audio_device(); + void make_current() const; bool can_use_audio(MovieAudioCursor *source);