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 }
get_value
Returns the variable's value.
get_value
Returns the variable's value.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
A MovieAudio is actually any source that provides a sequence of audio samples.
virtual int ready() const
Returns the number of audio samples that are ready to read.
A MovieAudio is actually any source that provides a sequence of audio samples.
Definition: movieAudio.h:44
get_filename
Returns the movie's filename.
Definition: movieAudio.h:52
virtual void set_active(bool)
Turn on/off Warning: not implemented.
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.
virtual void set_cache_limit(unsigned int count)
Set the number of sounds that the cache can hold.
virtual void uncache_sound(const Filename &)
Deletes a sample from the expiration queues.
virtual void stop_all_sounds()
Stop playback on all sounds managed by this manager.
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 shutdown()
Call this at exit time to shut down the audio system.
virtual PN_stdfloat audio_3d_get_distance_factor() const
Get value in units per meter.
virtual void clear_cache()
Clear out the sound cache.
virtual PN_stdfloat get_volume() const
Gets listener gain.
void set_play_rate(PN_stdfloat play_rate)
set the overall play rate
virtual void audio_3d_set_doppler_factor(PN_stdfloat factor)
Exaggerates or diminishes the Doppler effect.
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...
PN_stdfloat get_play_rate() const
get the overall speed/pitch/play rate
virtual void audio_3d_set_drop_off_factor(PN_stdfloat factor)
Control the effect distance has on audability.
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!...
virtual void update()
Perform all per-frame update functions.
virtual void set_volume(PN_stdfloat)
Sets listener gain.
Similar to MutexHolder, but for a reentrant mutex.
Definition: reMutexHolder.h:25
A reentrant mutex.
Definition: reMutex.h:34
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
Definition: thread.I:192
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
A hierarchy of directories and files that appears to be one continuous file system,...
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(AudioSound) OpenALAudioManager
This is what creates a sound instance.
AudioManager * Create_OpenALAudioManager()
Factory Function.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.