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