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&#39;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, even though the files may originate from several different sources that may not be related to the actual OS&#39;s 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&#39;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&#39;...
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! Both Panda3D an...
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&#39;s value.
A reentrant mutex.
Definition: reMutex.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.