Panda3D
openalAudioManager.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file openalAudioManager.cxx
10  * @author Ben Buchwald <bb2@alumni.cmu.edu>
11  */
12 
13 #include "pandabase.h"
14 
15 // Panda headers.
16 #include "config_audio.h"
17 #include "config_putil.h"
18 #include "config_express.h"
19 #include "config_openalAudio.h"
20 #include "openalAudioManager.h"
21 #include "openalAudioSound.h"
22 #include "virtualFileSystem.h"
23 #include "movieAudio.h"
24 #include "reMutexHolder.h"
25 
26 #include <algorithm>
27 
28 #ifndef ALC_DEFAULT_ALL_DEVICES_SPECIFIER
29 #define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012
30 #endif
31 
32 #ifndef ALC_ALL_DEVICES_SPECIFIER
33 #define ALC_ALL_DEVICES_SPECIFIER 0x1013
34 #endif
35 
36 using std::endl;
37 using std::string;
38 
39 TypeHandle OpenALAudioManager::_type_handle;
40 
41 ReMutex OpenALAudioManager::_lock;
42 int OpenALAudioManager::_active_managers = 0;
43 bool OpenALAudioManager::_openal_active = false;
44 ALCdevice* OpenALAudioManager::_device = nullptr;
45 ALCcontext* OpenALAudioManager::_context = nullptr;
46 
47 // This is the list of all OpenALAudioManager objects in the world. It must
48 // be a pointer rather than a concrete object, so it won't be destructed at
49 // exit time before we're done removing things from it.
50 OpenALAudioManager::Managers *OpenALAudioManager::_managers = nullptr;
51 
52 OpenALAudioManager::SourceCache *OpenALAudioManager::_al_sources = nullptr;
53 
54 
55 // Central dispatcher for audio errors.
56 void al_audio_errcheck(const char *context) {
57  ALenum result = alGetError();
58  if (result != AL_NO_ERROR) {
59  audio_error(context << ": " << alGetString(result) );
60  }
61 }
62 
63 void alc_audio_errcheck(const char *context,ALCdevice* device) {
64  ALCenum result = alcGetError(device);
65  if (result != ALC_NO_ERROR) {
66  audio_error(context << ": " << alcGetString(device,result) );
67  }
68 }
69 
70 /**
71  * Factory Function
72  */
74  audio_debug("Create_OpenALAudioManager()");
75  return new OpenALAudioManager;
76 }
77 
78 
79 /**
80  *
81  */
82 OpenALAudioManager::
83 OpenALAudioManager() {
84  ReMutexHolder holder(_lock);
85  if (_managers == nullptr) {
86  _managers = new Managers;
87  _al_sources = new SourceCache;
88  }
89 
90  _managers->insert(this);
91 
92  _cleanup_required = true;
93  _active = audio_active;
94  _volume = audio_volume;
95  _play_rate = 1.0f;
96 
97  _cache_limit = audio_cache_limit;
98 
99  _concurrent_sound_limit = 0;
100  _is_valid = true;
101 
102  // Init 3D attributes
103  _distance_factor = 1;
104  _drop_off_factor = 1;
105 
106  _position[0] = 0;
107  _position[1] = 0;
108  _position[2] = 0;
109 
110  _velocity[0] = 0;
111  _velocity[1] = 0;
112  _velocity[2] = 0;
113 
114  _forward_up[0] = 0;
115  _forward_up[1] = 0;
116  _forward_up[2] = 0;
117  _forward_up[3] = 0;
118  _forward_up[4] = 0;
119  _forward_up[5] = 0;
120 
121  // Initialization
122  audio_cat.init();
123  if (_active_managers == 0 || !_openal_active) {
124  _device = nullptr;
125  string dev_name = select_audio_device();
126 
127  if (!dev_name.empty()) {
128  // Open a specific device by name.
129  audio_cat.info() << "Using OpenAL device " << dev_name << "\n";
130  _device = alcOpenDevice(dev_name.c_str());
131 
132  if (_device == nullptr) {
133  audio_cat.error()
134  << "Couldn't open OpenAL device \"" << dev_name << "\", falling back to default device\n";
135  }
136  } else {
137  audio_cat.info() << "Using default OpenAL device\n";
138  }
139 
140  if (_device == nullptr) {
141  // Open the default device.
142  _device = alcOpenDevice(nullptr);
143 
144  if (_device == nullptr && dev_name != "OpenAL Soft") {
145  // Try the OpenAL Soft driver instead, which is fairly reliable.
146  _device = alcOpenDevice("OpenAL Soft");
147 
148  if (_device == nullptr) {
149  audio_cat.error()
150  << "Couldn't open default OpenAL device\n";
151  }
152  }
153  }
154 
155  if (_device != nullptr) {
156  // We managed to get a device open.
157  alcGetError(_device); // clear errors
158  _context = alcCreateContext(_device, nullptr);
159  alc_audio_errcheck("alcCreateContext(_device, NULL)", _device);
160  if (_context != nullptr) {
161  _openal_active = true;
162  }
163  }
164  }
165 
166  // We increment _active_managers regardless of possible errors above. The
167  // shutdown call will do the right thing when it's called, either way.
168  ++_active_managers;
169  nassertv(_active_managers>0);
170 
171  if (!_device || !_context) {
172  audio_error("OpenALAudioManager: No open device or context");
173  _is_valid = false;
174  } else {
175  alcGetError(_device); // clear errors
176  alcMakeContextCurrent(_context);
177  alc_audio_errcheck("alcMakeContextCurrent(_context)", _device);
178 
179  // set 3D sound characteristics as they are given in the configrc
180  audio_3d_set_doppler_factor(audio_doppler_factor);
181  audio_3d_set_distance_factor(audio_distance_factor);
182  audio_3d_set_drop_off_factor(audio_drop_off_factor);
183 
184  if (audio_cat.is_debug()) {
185  audio_cat.debug()
186  << "ALC_DEVICE_SPECIFIER:" << alcGetString(_device, ALC_DEVICE_SPECIFIER) << endl;
187  }
188  }
189 
190  if (audio_cat.is_debug()) {
191  audio_cat.debug() << "AL_RENDERER:" << alGetString(AL_RENDERER) << endl;
192  audio_cat.debug() << "AL_VENDOR:" << alGetString(AL_VENDOR) << endl;
193  audio_cat.debug() << "AL_VERSION:" << alGetString(AL_VERSION) << endl;
194  }
195 }
196 
197 /**
198  *
199  */
200 OpenALAudioManager::
201 ~OpenALAudioManager() {
202  ReMutexHolder holder(_lock);
203  nassertv(_managers != nullptr);
204  Managers::iterator mi = _managers->find(this);
205  nassertv(mi != _managers->end());
206  _managers->erase(mi);
207  cleanup();
208 }
209 
210 /**
211  * Call this at exit time to shut down the audio system. This will invalidate
212  * all currently-active AudioManagers and AudioSounds in the system. If you
213  * change your mind and want to play sounds again, you will have to recreate
214  * all of these objects.
215  */
217 shutdown() {
218  ReMutexHolder holder(_lock);
219  if (_managers != nullptr) {
220  Managers::iterator mi;
221  for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
222  (*mi)->cleanup();
223  }
224  }
225 
226  nassertv(_active_managers == 0);
227 }
228 
229 
230 /**
231  * This is mostly for debugging, but it it could be used to detect errors in a
232  * release build if you don't mind the cpu cost.
233  */
235 is_valid() {
236  return _is_valid;
237 }
238 
239 /**
240  * Enumerate the audio devices, selecting the one that is most appropriate or
241  * has been selected by the user.
242  */
243 string OpenALAudioManager::
244 select_audio_device() {
245  string selected_device = openal_device;
246 
247  const char *devices = nullptr;
248 
249  // This extension gives us all audio paths on all drivers.
250  if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE) {
251  string default_device = alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
252  devices = (const char *)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
253 
254  if (devices) {
255  if (audio_cat.is_debug()) {
256  audio_cat.debug() << "All OpenAL devices:\n";
257  }
258 
259  while (*devices) {
260  string device(devices);
261  devices += device.size() + 1;
262 
263  if (audio_cat.is_debug()) {
264  if (device == selected_device) {
265  audio_cat.debug() << " " << device << " [selected]\n";
266  } else if (device == default_device) {
267  audio_cat.debug() << " " << device << " [default]\n";
268  } else {
269  audio_cat.debug() << " " << device << "\n";
270  }
271  }
272  }
273  }
274  } else {
275  audio_cat.debug() << "ALC_ENUMERATE_ALL_EXT not supported\n";
276  }
277 
278  // This extension just gives us generic driver names, like "OpenAL Soft" and
279  // "Generic Software", rather than individual outputs.
280  if (alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT") == AL_TRUE) {
281  string default_device = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
282  devices = (const char *)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
283 
284  if (devices) {
285  if (audio_cat.is_debug()) {
286  audio_cat.debug() << "OpenAL drivers:\n";
287  }
288 
289  while (*devices) {
290  string device(devices);
291  devices += device.size() + 1;
292 
293  if (selected_device.empty() && device == "OpenAL Soft" &&
294  default_device == "Generic Software") {
295  // Prefer OpenAL Soft over the buggy Generic Software driver.
296  selected_device = "OpenAL Soft";
297  }
298 
299  if (audio_cat.is_debug()) {
300  if (device == selected_device) {
301  audio_cat.debug() << " " << device << " [selected]\n";
302  } else if (device == default_device) {
303  audio_cat.debug() << " " << device << " [default]\n";
304  } else {
305  audio_cat.debug() << " " << device << "\n";
306  }
307  }
308  }
309  }
310  } else {
311  audio_cat.debug() << "ALC_ENUMERATION_EXT not supported\n";
312  }
313 
314  return selected_device;
315 }
316 
317 /**
318  * This makes this manager's OpenAL context the current context. Needed
319  * before any parameter sets.
320  */
321 void OpenALAudioManager::
322 make_current() const {
323  // Since we only use one context, this is now a no-op.
324 }
325 
326 /**
327  * Returns true if the specified MovieAudioCursor can be used by this
328  * AudioManager. Mostly, this involves checking whether or not the format is
329  * implemented/supported.
330  */
331 bool OpenALAudioManager::
332 can_use_audio(MovieAudioCursor *source) {
333  ReMutexHolder holder(_lock);
334  int channels = source->audio_channels();
335  if ((channels != 1)&&(channels != 2)) {
336  audio_error("Currently, only mono and stereo are supported.");
337  return false;
338  }
339  return true;
340 }
341 
342 /**
343  * Returns true if the specified MovieAudio should be cached into RAM. A lot
344  * of conditions have to be met in order to allow caching - if any are not
345  * met, the file will be streamed.
346  */
347 bool OpenALAudioManager::
348 should_load_audio(MovieAudioCursor *source, int mode) {
349  ReMutexHolder holder(_lock);
350  if (mode == SM_stream) {
351  // If the user asked for streaming, give him streaming.
352  return false;
353  }
354  if (source->get_source()->get_filename().empty()) {
355  // Non-files cannot be preloaded.
356  return false;
357  }
358  if (source->ready() != 0x40000000) {
359  // Streaming sources cannot be preloaded.
360  return false;
361  }
362  if (source->length() > 3600.0) {
363  // Anything longer than an hour cannot be preloaded.
364  return false;
365  }
366  int channels = source->audio_channels();
367  int samples = (int)(source->length() * source->audio_rate());
368  int bytes = samples * channels * 2;
369  if ((mode == SM_heuristic)&&(bytes > audio_preload_threshold)) {
370  // In heuristic mode, if file is long, stream it.
371  return false;
372  }
373  return true;
374 }
375 
376 /**
377  * Obtains a SoundData for the specified sound.
378  *
379  * When you are done with the SoundData, you need to decrement the client
380  * count.
381  */
382 OpenALAudioManager::SoundData *OpenALAudioManager::
383 get_sound_data(MovieAudio *movie, int mode) {
384  ReMutexHolder holder(_lock);
385  const Filename &path = movie->get_filename();
386 
387  // Search for an already-cached sample or an already-opened stream.
388  if (!path.empty()) {
389 
390  if (mode != SM_stream) {
391  SampleCache::iterator lsmi=_sample_cache.find(path);
392  if (lsmi != _sample_cache.end()) {
393  SoundData *sd = (*lsmi).second;
394  increment_client_count(sd);
395  return sd;
396  }
397  }
398 
399  if (mode != SM_sample) {
400  ExpirationQueue::iterator exqi;
401  for (exqi=_expiring_streams.begin(); exqi!=_expiring_streams.end(); exqi++) {
402  SoundData *sd = (SoundData*)(*exqi);
403  if (sd->_movie->get_filename() == path) {
404  increment_client_count(sd);
405  return sd;
406  }
407  }
408  }
409  }
410 
411  PT(MovieAudioCursor) stream = movie->open();
412  if (stream == nullptr) {
413  audio_error("Cannot open file: "<<path);
414  return nullptr;
415  }
416 
417  if (!can_use_audio(stream)) {
418  audio_error("File is not in usable format: "<<path);
419  return nullptr;
420  }
421 
422  SoundData *sd = new SoundData();
423  sd->_client_count = 1;
424  sd->_manager = this;
425  sd->_movie = movie;
426  sd->_rate = stream->audio_rate();
427  sd->_channels = stream->audio_channels();
428  sd->_length = stream->length();
429  audio_debug("Creating: " << sd->_movie->get_filename().get_basename());
430  audio_debug(" - Rate: " << sd->_rate);
431  audio_debug(" - Channels: " << sd->_channels);
432  audio_debug(" - Length: " << sd->_length);
433 
434  if (should_load_audio(stream, mode)) {
435  audio_debug(path.get_basename() << ": loading as sample");
436  make_current();
437  alGetError(); // clear errors
438  sd->_sample = 0;
439  alGenBuffers(1, &sd->_sample);
440  al_audio_errcheck("alGenBuffers");
441  if (sd->_sample == 0) {
442  audio_error("Could not create an OpenAL buffer object");
443  delete sd;
444  return nullptr;
445  }
446  int channels = stream->audio_channels();
447  int samples = (int)(stream->length() * stream->audio_rate());
448  int16_t *data = new int16_t[samples * channels];
449  stream->read_samples(samples, data);
450  alBufferData(sd->_sample,
451  (channels>1) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16,
452  data, samples * channels * 2, stream->audio_rate());
453  delete[] data;
454  int err = alGetError();
455  if (err != AL_NO_ERROR) {
456  audio_error("could not fill OpenAL buffer object with data");
457  delete sd;
458  return nullptr;
459  }
460  _sample_cache.insert(SampleCache::value_type(path, sd));
461  } else {
462  audio_debug(path.get_basename() << ": loading as stream");
463  sd->_stream = stream;
464  }
465 
466  return sd;
467 }
468 
469 /**
470  * This is what creates a sound instance.
471  */
472 PT(AudioSound) OpenALAudioManager::
473 get_sound(MovieAudio *sound, bool positional, int mode) {
474  ReMutexHolder holder(_lock);
475  if(!is_valid()) {
476  return get_null_sound();
477  }
478  PT(OpenALAudioSound) oas =
479  new OpenALAudioSound(this, sound, positional, mode);
480 
481  if(!oas->_manager) {
482  // The sound cleaned itself up immediately. It pretty clearly didn't like
483  // something, so we should just return a null sound instead.
484  return get_null_sound();
485  }
486 
487  _all_sounds.insert(oas);
488  PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
489  return res;
490 }
491 
492 /**
493  * This is what creates a sound instance.
494  */
495 PT(AudioSound) OpenALAudioManager::
496 get_sound(const Filename &file_name, bool positional, int mode) {
497  ReMutexHolder holder(_lock);
498  if(!is_valid()) {
499  return get_null_sound();
500  }
501 
502  Filename path = file_name;
504  vfs->resolve_filename(path, get_model_path());
505 
506  if (path.empty()) {
507  audio_error("get_sound - invalid filename");
508  return nullptr;
509  }
510 
511  PT(MovieAudio) mva = MovieAudio::get(path);
512 
513  PT(OpenALAudioSound) oas =
514  new OpenALAudioSound(this, mva, positional, mode);
515 
516  if(!oas->_manager) {
517  // The sound cleaned itself up immediately. It pretty clearly didn't like
518  // something, so we should just return a null sound instead.
519  return get_null_sound();
520  }
521 
522  _all_sounds.insert(oas);
523  PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
524  return res;
525 }
526 
527 /**
528  * Deletes a sample from the expiration queues. If the sound is actively in
529  * use, then the sound cannot be deleted, and this function has no effect.
530  */
532 uncache_sound(const Filename &file_name) {
533  ReMutexHolder holder(_lock);
534  nassertv(is_valid());
535  Filename path = file_name;
536 
538  vfs->resolve_filename(path, get_model_path());
539 
540  SampleCache::iterator sci = _sample_cache.find(path);
541  if (sci == _sample_cache.end()) {
542  sci = _sample_cache.find(file_name);
543  }
544  if (sci != _sample_cache.end()) {
545  SoundData *sd = (*sci).second;
546  if (sd->_client_count == 0) {
547  _expiring_samples.erase(sd->_expire);
548  _sample_cache.erase(sci);
549  delete sd;
550  }
551  }
552 
553  ExpirationQueue::iterator exqi;
554  for (exqi = _expiring_streams.begin(); exqi != _expiring_streams.end();) {
555  SoundData *sd = (SoundData *)(*exqi);
556  if (sd->_client_count == 0) {
557  if (sd->_movie->get_filename() == path ||
558  sd->_movie->get_filename() == file_name) {
559  exqi = _expiring_streams.erase(exqi);
560  delete sd;
561  continue;
562  }
563  }
564  ++exqi;
565  }
566 }
567 
568 /**
569  * Clear out the sound cache.
570  */
572 clear_cache() {
573  ReMutexHolder holder(_lock);
574  discard_excess_cache(0);
575 }
576 
577 /**
578  * Set the number of sounds that the cache can hold.
579  */
581 set_cache_limit(unsigned int count) {
582  ReMutexHolder holder(_lock);
583  _cache_limit=count;
584  discard_excess_cache(count);
585 }
586 
587 /**
588  *
589  */
590 unsigned int OpenALAudioManager::
591 get_cache_limit() const {
592  return _cache_limit;
593 }
594 
595 /**
596  *
597  */
598 void OpenALAudioManager::
599 release_sound(OpenALAudioSound* audioSound) {
600  ReMutexHolder holder(_lock);
601  AllSounds::iterator ai = _all_sounds.find(audioSound);
602  if (ai != _all_sounds.end()) {
603  _all_sounds.erase(ai);
604  }
605 }
606 
607 /**
608  *
609  * Sets listener gain
610  */
611 void OpenALAudioManager::set_volume(PN_stdfloat volume) {
612  ReMutexHolder holder(_lock);
613  if (_volume!=volume) {
614  _volume = volume;
615 
616  // Tell our AudioSounds to adjust:
617  AllSounds::iterator i=_all_sounds.begin();
618  for (; i!=_all_sounds.end(); ++i) {
619  (**i).set_volume((**i).get_volume());
620  }
621 
622  /*
623  // this was neat alternative to the above look when we had a seperate
624  // context for each manager
625  make_current();
626 
627  alGetError(); // clear errors
628  alListenerf(AL_GAIN,(ALfloat)_volume);
629  al_audio_errcheck("alListerf(AL_GAIN)");*/
630  }
631 }
632 
633 /**
634  *
635  * Gets listener gain
636  */
638 get_volume() const {
639  return _volume;
640 }
641 
642 /**
643  * set the overall play rate
644  */
646 set_play_rate(PN_stdfloat play_rate) {
647  ReMutexHolder holder(_lock);
648  if (_play_rate!=play_rate) {
649  _play_rate = play_rate;
650  // Tell our AudioSounds to adjust:
651  AllSounds::iterator i=_all_sounds.begin();
652  for (; i!=_all_sounds.end(); ++i) {
653  (**i).set_play_rate((**i).get_play_rate());
654  }
655  }
656 }
657 
658 /**
659  * get the overall speed/pitch/play rate
660  */
662 get_play_rate() const {
663  return _play_rate;
664 }
665 
666 /**
667  * Turn on/off Warning: not implemented.
668  */
670 set_active(bool active) {
671  ReMutexHolder holder(_lock);
672  if (_active!=active) {
673  _active=active;
674  // Tell our AudioSounds to adjust:
675  AllSounds::iterator i=_all_sounds.begin();
676  for (; i!=_all_sounds.end(); ++i) {
677  (**i).set_active(_active);
678  }
679  }
680 }
681 
682 /**
683  *
684  */
685 bool OpenALAudioManager::
686 get_active() const {
687  return _active;
688 }
689 
690 /**
691  * Set position of the "ear" that picks up 3d sounds NOW LISTEN UP!!! THIS IS
692  * IMPORTANT! Both Panda3D and OpenAL use a right handed coordinate system.
693  * But there is a major difference! In Panda3D the Y-Axis is going into the
694  * Screen and the Z-Axis is going up. In OpenAL the Y-Axis is going up and
695  * the Z-Axis is coming out of the screen. The solution is simple, we just
696  * flip the Y and Z axis and negate the Z, as we move coordinates from Panda
697  * to OpenAL and back. What does did mean to average Panda user? Nothing,
698  * they shouldn't notice anyway. But if you decide to do any 3D audio work in
699  * here you have to keep it in mind. I told you, so you can't say I didn't.
700  */
702 audio_3d_set_listener_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat vy, PN_stdfloat vz, PN_stdfloat fx, PN_stdfloat fy, PN_stdfloat fz, PN_stdfloat ux, PN_stdfloat uy, PN_stdfloat uz) {
703  ReMutexHolder holder(_lock);
704  _position[0] = px;
705  _position[1] = pz;
706  _position[2] = -py;
707 
708  _velocity[0] = vx;
709  _velocity[1] = vz;
710  _velocity[2] = -vy;
711 
712  _forward_up[0] = fx;
713  _forward_up[1] = fz;
714  _forward_up[2] = -fy;
715 
716  _forward_up[3] = ux;
717  _forward_up[4] = uz;
718  _forward_up[5] = -uy;
719 
720 
721  make_current();
722 
723  alGetError(); // clear errors
724  alListenerfv(AL_POSITION,_position);
725  al_audio_errcheck("alListerfv(AL_POSITION)");
726  alListenerfv(AL_VELOCITY,_velocity);
727  al_audio_errcheck("alListerfv(AL_VELOCITY)");
728  alListenerfv(AL_ORIENTATION,_forward_up);
729  al_audio_errcheck("alListerfv(AL_ORIENTATION)");
730 }
731 
732 /**
733  * Get position of the "ear" that picks up 3d sounds
734  */
736 audio_3d_get_listener_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz, PN_stdfloat *fx, PN_stdfloat *fy, PN_stdfloat *fz, PN_stdfloat *ux, PN_stdfloat *uy, PN_stdfloat *uz) {
737  ReMutexHolder holder(_lock);
738  *px = _position[0];
739  *py = -_position[2];
740  *pz = _position[1];
741 
742  *vx = _velocity[0];
743  *vy = -_velocity[2];
744  *vz = _velocity[1];
745 
746  *fx = _forward_up[0];
747  *fy = -_forward_up[2];
748  *fz = _forward_up[1];
749 
750  *ux = _forward_up[3];
751  *uy = -_forward_up[5];
752  *uz = _forward_up[4];
753 }
754 
755 /**
756  * Set value in units per meter
757  * WARNING: OpenAL has no distance factor but we use this as a scale
758  * on the min/max distances of sounds to preserve FMOD compatibility.
759  * Also adjusts the speed of sound to compensate for unit difference.
760  */
762 audio_3d_set_distance_factor(PN_stdfloat factor) {
763  ReMutexHolder holder(_lock);
764  _distance_factor = factor;
765 
766  make_current();
767 
768  alGetError(); // clear errors
769 
770  if (_distance_factor>0) {
771  alSpeedOfSound(343.3*_distance_factor);
772  al_audio_errcheck("alSpeedOfSound()");
773  // resets the doppler factor to the correct setting in case it was set to
774  // 0.0 by a distance_factor<=0.0
775  alDopplerFactor(_doppler_factor);
776  al_audio_errcheck("alDopplerFactor()");
777  } else {
778  audio_debug("can't set speed of sound if distance_factor <=0.0, setting doppler factor to 0.0 instead");
779  alDopplerFactor(0.0);
780  al_audio_errcheck("alDopplerFactor()");
781  }
782 
783  AllSounds::iterator i=_all_sounds.begin();
784  for (; i!=_all_sounds.end(); ++i) {
785  (**i).set_3d_min_distance((**i).get_3d_min_distance());
786  (**i).set_3d_max_distance((**i).get_3d_max_distance());
787  }
788 }
789 
790 /**
791  * Get value in units per meter
792  */
795  return _distance_factor;
796 }
797 
798 /**
799  * Exaggerates or diminishes the Doppler effect. Defaults to 1.0
800  */
802 audio_3d_set_doppler_factor(PN_stdfloat factor) {
803  ReMutexHolder holder(_lock);
804  _doppler_factor = factor;
805 
806  make_current();
807 
808  alGetError(); // clear errors
809  alDopplerFactor(_doppler_factor);
810  al_audio_errcheck("alDopplerFactor()");
811 }
812 
813 /**
814  *
815  */
816 PN_stdfloat OpenALAudioManager::
817 audio_3d_get_doppler_factor() const {
818  return _doppler_factor;
819 }
820 
821 /**
822  * Control the effect distance has on audability. Defaults to 1.0
823  */
825 audio_3d_set_drop_off_factor(PN_stdfloat factor) {
826  ReMutexHolder holder(_lock);
827  _drop_off_factor = factor;
828 
829  AllSounds::iterator i=_all_sounds.begin();
830  for (; i!=_all_sounds.end(); ++i) {
831  (**i).set_3d_drop_off_factor((**i).get_3d_drop_off_factor());
832  }
833 }
834 
835 /**
836  *
837  */
838 PN_stdfloat OpenALAudioManager::
839 audio_3d_get_drop_off_factor() const {
840  return _drop_off_factor;
841 }
842 
843 /**
844  * Inform the manager that a sound is about to play. The manager will add
845  * this sound to the table of sounds that are playing, and will allocate a
846  * source to this sound.
847  */
848 void OpenALAudioManager::
849 starting_sound(OpenALAudioSound* audio) {
850  ReMutexHolder holder(_lock);
851  ALuint source=0;
852 
853  // If the sound already has a source, we don't need to do anything.
854  if (audio->_source) {
855  return;
856  }
857 
858  // first give all sounds that have finished a chance to stop, so that these
859  // get stopped first
860  update();
861 
862  if (_concurrent_sound_limit) {
863  reduce_sounds_playing_to(_concurrent_sound_limit-1); // because we're about to add one
864  }
865 
866  // get a source from the source pool or create a new source
867  if (_al_sources->empty()) {
868  make_current();
869  alGetError(); // clear errors
870  alGenSources(1,&source);
871  ALenum result = alGetError();
872  if (result!=AL_NO_ERROR) {
873  audio_error("alGenSources(): " << alGetString(result) );
874  // if we can't create any more sources, set stop a sound to free a
875  // source
876  reduce_sounds_playing_to(_sounds_playing.size()-1);
877  source = 0;
878  }
879  }
880  // get a source from the source bool if we didn't just allocate one
881  if (!source && !_al_sources->empty()) {
882  source = *(_al_sources->begin());
883  _al_sources->erase(source);
884  }
885 
886  audio->_source = source;
887 
888  if (source)
889  _sounds_playing.insert(audio);
890 }
891 
892 /**
893  * Inform the manager that a sound is finished or someone called stop on the
894  * sound (this should not be called if a sound is only paused).
895  */
896 void OpenALAudioManager::
897 stopping_sound(OpenALAudioSound* audio) {
898  ReMutexHolder holder(_lock);
899  if (audio->_source) {
900  _al_sources->insert(audio->_source);
901  audio->_source = 0;
902  }
903  _sounds_playing.erase(audio); // This could cause the sound to destruct.
904 }
905 
906 /**
907  *
908  */
909 void OpenALAudioManager::
910 set_concurrent_sound_limit(unsigned int limit) {
911  ReMutexHolder holder(_lock);
912  _concurrent_sound_limit = limit;
913  reduce_sounds_playing_to(_concurrent_sound_limit);
914 }
915 
916 /**
917  *
918  */
919 unsigned int OpenALAudioManager::
920 get_concurrent_sound_limit() const {
921  return _concurrent_sound_limit;
922 }
923 
924 /**
925  *
926  */
927 void OpenALAudioManager::
928 reduce_sounds_playing_to(unsigned int count) {
929  ReMutexHolder holder(_lock);
930  // first give all sounds that have finished a chance to stop, so that these
931  // get stopped first
932  update();
933 
934  int limit = _sounds_playing.size() - count;
935  while (limit-- > 0) {
936  SoundsPlaying::iterator sound = _sounds_playing.begin();
937  nassertv(sound != _sounds_playing.end());
938  // When the user stops a sound, there is still a PT in the user's hand.
939  // When we stop a sound here, however, this can remove the last PT. This
940  // can cause an ugly recursion where stop calls the destructor, and the
941  // destructor calls stop. To avoid this, we create a temporary PT, stop
942  // the sound, and then release the PT.
943  PT(OpenALAudioSound) s = (*sound);
944  s->stop();
945  }
946 }
947 
948 /**
949  * Stop playback on all sounds managed by this manager.
950  */
952 stop_all_sounds() {
953  ReMutexHolder holder(_lock);
954  reduce_sounds_playing_to(0);
955 }
956 
957 /**
958  * Perform all per-frame update functions.
959  */
961 update() {
962  ReMutexHolder holder(_lock);
963 
964  // See if any of our playing sounds have ended we must first collect a
965  // seperate list of finished sounds and then iterated over those again
966  // calling their finished method. We can't call finished() within a loop
967  // iterating over _sounds_playing since finished() modifies _sounds_playing
968  SoundsPlaying sounds_finished;
969 
970  double rtc = TrueClock::get_global_ptr()->get_short_time();
971  SoundsPlaying::iterator i=_sounds_playing.begin();
972  for (; i!=_sounds_playing.end(); ++i) {
973  OpenALAudioSound *sound = (*i);
974  sound->pull_used_buffers();
975  sound->push_fresh_buffers();
976  sound->restart_stalled_audio();
977  sound->cache_time(rtc);
978  if ((sound->_source == 0)||
979  ((sound->_stream_queued.size() == 0)&&
980  (sound->_loops_completed >= sound->_playing_loops))) {
981  sounds_finished.insert(*i);
982  }
983  }
984 
985  i=sounds_finished.begin();
986  for (; i!=sounds_finished.end(); ++i) {
987  (**i).finished();
988  }
989 }
990 
991 
992 /**
993  * Shuts down the audio manager and releases any resources associated with it.
994  * Also cleans up all AudioSounds created via the manager.
995  */
996 void OpenALAudioManager::
997 cleanup() {
998  ReMutexHolder holder(_lock);
999  if (!_cleanup_required) {
1000  return;
1001  }
1002 
1003  stop_all_sounds();
1004 
1005  AllSounds sounds(_all_sounds);
1006  AllSounds::iterator ai;
1007  for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
1008  (*ai)->cleanup();
1009  }
1010 
1011  clear_cache();
1012 
1013  nassertv(_active_managers > 0);
1014  --_active_managers;
1015 
1016  if (_active_managers == 0) {
1017  if (_openal_active) {
1018  // empty the source cache
1019  int i=0;
1020  ALuint *sources;
1021  sources = new ALuint[_al_sources->size()];
1022  for (SourceCache::iterator si = _al_sources->begin(); si!=_al_sources->end(); ++si) {
1023  sources[i++]=*si;
1024  }
1025  make_current();
1026  alGetError(); // clear errors
1027  alDeleteSources(_al_sources->size(),sources);
1028  al_audio_errcheck("alDeleteSources()");
1029  delete [] sources;
1030  _al_sources->clear();
1031 
1032  // make sure that the context is not current when it is destroyed
1033  alcGetError(_device); // clear errors
1034  alcMakeContextCurrent(nullptr);
1035  alc_audio_errcheck("alcMakeContextCurrent(NULL)",_device);
1036 
1037  alcDestroyContext(_context);
1038  alc_audio_errcheck("alcDestroyContext(_context)",_device);
1039  _context = nullptr;
1040 
1041  if (_device) {
1042  audio_debug("Going to try to close openAL");
1043  alcCloseDevice(_device);
1044  // alc_audio_errcheck("alcCloseDevice(_device)",_device);
1045  _device = nullptr;
1046  audio_debug("openAL Closed");
1047  }
1048 
1049  _openal_active = false;
1050  }
1051  }
1052  _cleanup_required = false;
1053 }
1054 
1055 /**
1056  *
1057  */
1058 OpenALAudioManager::SoundData::
1059 SoundData() :
1060  _manager(nullptr),
1061  _sample(0),
1062  _stream(nullptr),
1063  _length(0.0),
1064  _rate(0),
1065  _channels(0),
1066  _client_count(0)
1067 {
1068 }
1069 
1070 /**
1071  *
1072  */
1073 OpenALAudioManager::SoundData::
1074 ~SoundData() {
1075  ReMutexHolder holder(OpenALAudioManager::_lock);
1076  if (_sample != 0) {
1077  if (_manager->_is_valid) {
1078  _manager->make_current();
1079  _manager->delete_buffer(_sample);
1080  }
1081  _sample = 0;
1082  }
1083 }
1084 
1085 /**
1086  * Increments the SoundData's client count. Any SoundData that is actively in
1087  * use (ie, has a client) is removed entirely from the expiration queue.
1088  */
1089 void OpenALAudioManager::
1090 increment_client_count(SoundData *sd) {
1091  ReMutexHolder holder(_lock);
1092  sd->_client_count += 1;
1093  audio_debug("Incrementing: " << sd->_movie->get_filename().get_basename() << " " << sd->_client_count);
1094  if (sd->_client_count == 1) {
1095  if (sd->_sample) {
1096  _expiring_samples.erase(sd->_expire);
1097  } else {
1098  _expiring_streams.erase(sd->_expire);
1099  }
1100  }
1101 }
1102 
1103 /**
1104  * Decrements the SoundData's client count. Sounds that are no longer in use
1105  * (ie, have no clients) go into the expiration queue. When the expiration
1106  * queue reaches the cache limit, the first item on the queue is freed.
1107  */
1108 void OpenALAudioManager::
1109 decrement_client_count(SoundData *sd) {
1110  ReMutexHolder holder(_lock);
1111  sd->_client_count -= 1;
1112  audio_debug("Decrementing: " << sd->_movie->get_filename().get_basename() << " " << sd->_client_count);
1113  if (sd->_client_count == 0) {
1114  if (sd->_sample) {
1115  _expiring_samples.push_back(sd);
1116  sd->_expire = _expiring_samples.end();
1117  sd->_expire--;
1118  } else {
1119  _expiring_streams.push_back(sd);
1120  sd->_expire = _expiring_streams.end();
1121  sd->_expire--;
1122  }
1123  discard_excess_cache(_cache_limit);
1124  }
1125 }
1126 
1127 /**
1128  * Discards sounds from the sound cache until the number of sounds remaining
1129  * is under the limit.
1130  */
1131 void OpenALAudioManager::
1132 discard_excess_cache(int sample_limit) {
1133  ReMutexHolder holder(_lock);
1134  int stream_limit = 5;
1135 
1136  while (((int)_expiring_samples.size()) > sample_limit) {
1137  SoundData *sd = (SoundData*)(_expiring_samples.front());
1138  nassertv(sd->_client_count == 0);
1139  nassertv(sd->_expire == _expiring_samples.begin());
1140  _expiring_samples.pop_front();
1141  _sample_cache.erase(_sample_cache.find(sd->_movie->get_filename()));
1142  audio_debug("Expiring: " << sd->_movie->get_filename().get_basename());
1143  delete sd;
1144  }
1145 
1146  while (((int)_expiring_streams.size()) > stream_limit) {
1147  SoundData *sd = (SoundData*)(_expiring_streams.front());
1148  nassertv(sd->_client_count == 0);
1149  nassertv(sd->_expire == _expiring_streams.begin());
1150  _expiring_streams.pop_front();
1151  audio_debug("Expiring: " << sd->_movie->get_filename().get_basename());
1152  delete sd;
1153  }
1154 }
1155 
1156 /**
1157  * Deletes an OpenAL buffer. This is a special function because some
1158  * implementations of OpenAL (e.g. Apple's) don't unlock the buffers
1159  * immediately, due to needing to coordinate with another thread. If this is
1160  * the case, the alDeleteBuffers call will error back with AL_INVALID_OPERATION
1161  * as if trying to delete an actively-used buffer, which will tell us to wait a
1162  * bit and try again.
1163  */
1164 void OpenALAudioManager::
1165 delete_buffer(ALuint buffer) {
1166  ReMutexHolder holder(_lock);
1167  int tries = 0;
1168  ALuint error;
1169 
1170  // Keep trying until we succeed (or give up).
1171  while (true) {
1172  alDeleteBuffers(1, &buffer);
1173  error = alGetError();
1174 
1175  if (error == AL_NO_ERROR) {
1176  // Success! This will happen right away 99% of the time.
1177  return;
1178  } else if (error != AL_INVALID_OPERATION) {
1179  // We weren't expecting that. This should be reported.
1180  break;
1181  } else if (tries >= openal_buffer_delete_retries.get_value()) {
1182  // We ran out of retries. Give up.
1183  break;
1184  } else {
1185  // Make another try after (delay * 2^n) seconds.
1186  Thread::sleep(openal_buffer_delete_delay.get_value() * (1 << tries));
1187  tries++;
1188  }
1189  }
1190 
1191  // If we got here, one of the breaks above happened, indicating an error.
1192  audio_error("failed to delete a buffer: " << alGetString(error) );
1193 }
OpenALAudioManager::audio_3d_get_distance_factor
virtual PN_stdfloat audio_3d_get_distance_factor() const
Get value in units per meter.
Definition: openalAudioManager.cxx:794
MovieAudio::get_filename
get_filename
Returns the movie's filename.
Definition: movieAudio.h:52
openalAudioSound.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_putil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigVariableDouble::get_value
get_value
Returns the variable's value.
Definition: configVariableDouble.h:43
ReMutex
A reentrant mutex.
Definition: reMutex.h:34
ReMutexHolder
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:25
pandabase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioManager::clear_cache
virtual void clear_cache()
Clear out the sound cache.
Definition: openalAudioManager.cxx:572
OpenALAudioManager::get_volume
virtual PN_stdfloat get_volume() const
Gets listener gain.
Definition: openalAudioManager.cxx:638
Thread::sleep
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
Definition: thread.I:192
OpenALAudioManager::set_play_rate
void set_play_rate(PN_stdfloat play_rate)
set the overall play rate
Definition: openalAudioManager.cxx:646
OpenALAudioSound
Definition: openalAudioSound.h:32
OpenALAudioManager::set_volume
virtual void set_volume(PN_stdfloat)
Sets listener gain.
Definition: openalAudioManager.cxx:611
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
OpenALAudioManager::audio_3d_set_distance_factor
virtual void audio_3d_set_distance_factor(PN_stdfloat factor)
Set value in units per meter WARNING: OpenAL has no distance factor but we use this as a scale on the...
Definition: openalAudioManager.cxx:762
OpenALAudioManager::set_active
virtual void set_active(bool)
Turn on/off Warning: not implemented.
Definition: openalAudioManager.cxx:670
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition: virtualFileSystem.h:40
OpenALAudioManager::shutdown
virtual void shutdown()
Call this at exit time to shut down the audio system.
Definition: openalAudioManager.cxx:217
MovieAudioCursor::ready
virtual int ready() const
Returns the number of audio samples that are ready to read.
Definition: movieAudioCursor.cxx:161
ConfigVariableInt::get_value
get_value
Returns the variable's value.
Definition: configVariableInt.h:43
OpenALAudioManager::set_cache_limit
virtual void set_cache_limit(unsigned int count)
Set the number of sounds that the cache can hold.
Definition: openalAudioManager.cxx:581
OpenALAudioManager::update
virtual void update()
Perform all per-frame update functions.
Definition: openalAudioManager.cxx:961
OpenALAudioManager::audio_3d_set_drop_off_factor
virtual void audio_3d_set_drop_off_factor(PN_stdfloat factor)
Control the effect distance has on audability.
Definition: openalAudioManager.cxx:825
reMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioManager::audio_3d_set_doppler_factor
virtual void audio_3d_set_doppler_factor(PN_stdfloat factor)
Exaggerates or diminishes the Doppler effect.
Definition: openalAudioManager.cxx:802
OpenALAudioManager::audio_3d_set_listener_attributes
virtual void audio_3d_set_listener_attributes(PN_stdfloat px, PN_stdfloat py, PN_stdfloat pz, PN_stdfloat vx, PN_stdfloat xy, PN_stdfloat xz, PN_stdfloat fx, PN_stdfloat fy, PN_stdfloat fz, PN_stdfloat ux, PN_stdfloat uy, PN_stdfloat uz)
Set position of the "ear" that picks up 3d sounds NOW LISTEN UP!!! THIS IS IMPORTANT!...
Definition: openalAudioManager.cxx:702
OpenALAudioManager
Definition: openalAudioManager.h:39
OpenALAudioManager::is_valid
virtual bool is_valid()
This is mostly for debugging, but it it could be used to detect errors in a release build if you don'...
Definition: openalAudioManager.cxx:235
movieAudio.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MovieAudioCursor
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudioCursor.h:34
config_audio.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioManager::uncache_sound
virtual void uncache_sound(const Filename &)
Deletes a sample from the expiration queues.
Definition: openalAudioManager.cxx:532
MovieAudio
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudio.h:44
Create_OpenALAudioManager
AudioManager * Create_OpenALAudioManager()
Factory Function.
Definition: openalAudioManager.cxx:73
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition: virtualFileSystem.cxx:741
virtualFileSystem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AudioSound
Definition: audioSound.h:25
TrueClock::get_global_ptr
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
OpenALAudioManager::stop_all_sounds
virtual void stop_all_sounds()
Stop playback on all sounds managed by this manager.
Definition: openalAudioManager.cxx:952
AudioManager
Definition: audioManager.h:28
VirtualFileSystem::resolve_filename
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
Definition: virtualFileSystem.cxx:640
openalAudioManager.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT
PT(AudioSound) OpenALAudioManager
This is what creates a sound instance.
Definition: openalAudioManager.cxx:472
config_express.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
OpenALAudioManager::audio_3d_get_listener_attributes
virtual void audio_3d_get_listener_attributes(PN_stdfloat *px, PN_stdfloat *py, PN_stdfloat *pz, PN_stdfloat *vx, PN_stdfloat *vy, PN_stdfloat *vz, PN_stdfloat *fx, PN_stdfloat *fy, PN_stdfloat *fz, PN_stdfloat *ux, PN_stdfloat *uy, PN_stdfloat *uz)
Get position of the "ear" that picks up 3d sounds.
Definition: openalAudioManager.cxx:736
Filename::get_basename
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
OpenALAudioManager::get_play_rate
PN_stdfloat get_play_rate() const
get the overall speed/pitch/play rate
Definition: openalAudioManager.cxx:662
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
config_openalAudio.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pset
This is our own Panda specialization on the default STL set.
Definition: pset.h:49