mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-07 04:11:51 -04:00
thread protection in miles
This commit is contained in:
parent
3fe0ad1080
commit
b3c42f22ac
@ -27,12 +27,14 @@
|
|||||||
#include "config_express.h"
|
#include "config_express.h"
|
||||||
#include "virtualFileSystem.h"
|
#include "virtualFileSystem.h"
|
||||||
#include "nullAudioSound.h"
|
#include "nullAudioSound.h"
|
||||||
|
#include "mutexHolder.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
TypeHandle MilesAudioManager::_type_handle;
|
TypeHandle MilesAudioManager::_type_handle;
|
||||||
|
|
||||||
|
Mutex *MilesAudioManager::_static_lock;
|
||||||
int MilesAudioManager::_active_managers = 0;
|
int MilesAudioManager::_active_managers = 0;
|
||||||
bool MilesAudioManager::_miles_active = false;
|
bool MilesAudioManager::_miles_active = false;
|
||||||
HDLSFILEID MilesAudioManager::_dls_field = NULL;
|
HDLSFILEID MilesAudioManager::_dls_field = NULL;
|
||||||
@ -59,6 +61,18 @@ MilesAudioManager::
|
|||||||
MilesAudioManager() {
|
MilesAudioManager() {
|
||||||
audio_debug("MilesAudioManager::MilesAudioManager(), this = "
|
audio_debug("MilesAudioManager::MilesAudioManager(), this = "
|
||||||
<< (void *)this);
|
<< (void *)this);
|
||||||
|
if (_static_lock == NULL) {
|
||||||
|
Mutex *new_lock = new Mutex;
|
||||||
|
void *result = AtomicAdjust::compare_and_exchange_ptr((void * TVOLATILE &)_static_lock, (void *)NULL, (void *)new_lock);
|
||||||
|
if (result != NULL) {
|
||||||
|
// Someone else must have assigned the mutex first. OK.
|
||||||
|
nassertv(_static_lock != new_lock);
|
||||||
|
delete new_lock;
|
||||||
|
}
|
||||||
|
nassertv((Mutex * TVOLATILE &)_static_lock != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
MutexHolder st_holder(*(Mutex * TVOLATILE &)_static_lock);
|
||||||
if (_managers == (Managers *)NULL) {
|
if (_managers == (Managers *)NULL) {
|
||||||
_managers = new Managers;
|
_managers = new Managers;
|
||||||
}
|
}
|
||||||
@ -165,14 +179,22 @@ MilesAudioManager() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
MilesAudioManager::
|
MilesAudioManager::
|
||||||
~MilesAudioManager() {
|
~MilesAudioManager() {
|
||||||
|
{
|
||||||
|
MutexHolder st_holder(*_static_lock);
|
||||||
audio_debug("MilesAudioManager::~MilesAudioManager(), this = "
|
audio_debug("MilesAudioManager::~MilesAudioManager(), this = "
|
||||||
<< (void *)this);
|
<< (void *)this);
|
||||||
nassertv(_managers != (Managers *)NULL);
|
nassertv(_managers != (Managers *)NULL);
|
||||||
Managers::iterator mi = _managers->find(this);
|
Managers::iterator mi = _managers->find(this);
|
||||||
nassertv(mi != _managers->end());
|
if (mi != _managers->end()) {
|
||||||
|
// The manager might already have been removed from the list, if
|
||||||
|
// the user has already called shutdown().
|
||||||
|
nassertv(!_cleanup_required);
|
||||||
_managers->erase(mi);
|
_managers->erase(mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
audio_debug("MilesAudioManager::~MilesAudioManager() finished");
|
audio_debug("MilesAudioManager::~MilesAudioManager() finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,27 +209,60 @@ MilesAudioManager::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
shutdown() {
|
shutdown() {
|
||||||
|
Managers old_managers;
|
||||||
|
{
|
||||||
|
MutexHolder st_holder(*_static_lock);
|
||||||
|
|
||||||
audio_debug("shutdown(), _miles_active = " << _miles_active);
|
audio_debug("shutdown(), _miles_active = " << _miles_active);
|
||||||
if (_managers != (Managers *)NULL) {
|
if (_managers != (Managers *)NULL) {
|
||||||
Managers::iterator mi;
|
old_managers.swap(*_managers);
|
||||||
for (mi = _managers->begin(); mi != _managers->end(); ++mi) {
|
|
||||||
(*mi)->cleanup();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We insist on cleaning up our manager pointers, rather than
|
||||||
|
// relying on their destructors, since there might be outstanding
|
||||||
|
// pointers to these somewhere that would otherwise prevent them
|
||||||
|
// from being cleaned up and therefore prevent Miles from being shut
|
||||||
|
// down properly. In order for this to work, we must write
|
||||||
|
// cleanup() so that it is safe to call it twice.
|
||||||
|
Managers::iterator mi;
|
||||||
|
for (mi = old_managers.begin(); mi != old_managers.end(); ++mi) {
|
||||||
|
(*mi)->cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another thread might conceivably have started up a new manager
|
||||||
|
// after we called shutdown(), which is technically legal and would
|
||||||
|
// incorrectly trigger the following assertion. However, presumably
|
||||||
|
// shutdown() will only be called as the application is shutting
|
||||||
|
// down anyway, and there won't be any other threads still out there
|
||||||
|
// creating audio managers (and if there were, it would defeat the
|
||||||
|
// purpose of shutdown() anyway).
|
||||||
nassertv(_active_managers == 0);
|
nassertv(_active_managers == 0);
|
||||||
|
|
||||||
audio_debug("shutdown() finished");
|
audio_debug("shutdown() finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MilesAudioManager::is_valid
|
// Function: MilesAudioManager::is_valid
|
||||||
// Access:
|
// Access: Public
|
||||||
// Description: This is mostly for debugging, but it it could be
|
// Description: This is mostly for debugging, but it it could be
|
||||||
// used to detect errors in a release build if you
|
// used to detect errors in a release build if you
|
||||||
// don't mind the cpu cost.
|
// don't mind the cpu cost.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool MilesAudioManager::
|
bool MilesAudioManager::
|
||||||
is_valid() {
|
is_valid() {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
|
return do_is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MilesAudioManager::do_is_valid
|
||||||
|
// Access: Private
|
||||||
|
// Description: Assumes the lock is already held.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool MilesAudioManager::
|
||||||
|
do_is_valid() {
|
||||||
bool check=true;
|
bool check=true;
|
||||||
if (_sounds.size() != _lru.size()) {
|
if (_sounds.size() != _lru.size()) {
|
||||||
audio_debug("-- Error _sounds.size() != _lru.size() --");
|
audio_debug("-- Error _sounds.size() != _lru.size() --");
|
||||||
@ -320,59 +375,82 @@ get_sound(const string& file_name, bool) {
|
|||||||
return get_null_sound();
|
return get_null_sound();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(is_valid());
|
|
||||||
Filename path = file_name;
|
Filename path = file_name;
|
||||||
|
|
||||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||||
vfs->resolve_filename(path, get_sound_path());
|
vfs->resolve_filename(path, get_sound_path());
|
||||||
audio_debug(" resolved file_name is '"<<path<<"'");
|
audio_debug(" resolved file_name is '"<<path<<"'");
|
||||||
|
|
||||||
|
const string *cache_path = NULL;
|
||||||
PT(SoundData) sd;
|
PT(SoundData) sd;
|
||||||
|
|
||||||
// Get the sound, either from the cache or from a loader:
|
// Get the sound, either from the cache or from a loader:
|
||||||
SoundMap::const_iterator si=_sounds.find(path);
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
|
assert(do_is_valid());
|
||||||
|
|
||||||
|
SoundMap::const_iterator si = _sounds.find(path);
|
||||||
if (si != _sounds.end()) {
|
if (si != _sounds.end()) {
|
||||||
// ...found the sound in the cache.
|
// ...found the sound in the cache.
|
||||||
|
cache_path = &((*si).first);
|
||||||
sd = (*si).second;
|
sd = (*si).second;
|
||||||
audio_debug(" sound found in pool 0x" << (void*)sd);
|
audio_debug(" sound found in pool 0x" << (void*)sd);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (sd == (SoundData *)NULL) {
|
||||||
// ...the sound was not found in the cache/pool.
|
// ...the sound was not found in the cache/pool.
|
||||||
|
_lock.release();
|
||||||
sd = load(path);
|
sd = load(path);
|
||||||
|
_lock.lock();
|
||||||
|
|
||||||
if (sd != (SoundData *)NULL) {
|
if (sd != (SoundData *)NULL) {
|
||||||
|
SoundMap::const_iterator si = _sounds.find(path);
|
||||||
|
if (si != _sounds.end()) {
|
||||||
|
// Oops, someone else must have just put it in the cache.
|
||||||
|
// Throw away the sound object we just loaded.
|
||||||
|
cache_path = &((*si).first);
|
||||||
|
sd = (*si).second;
|
||||||
|
audio_debug(" sound found in pool 0x" << (void*)sd);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// OK, put the sound object we just loaded into the cache.
|
||||||
while (_sounds.size() >= (unsigned int)_cache_limit) {
|
while (_sounds.size() >= (unsigned int)_cache_limit) {
|
||||||
uncache_a_sound();
|
uncache_a_sound();
|
||||||
}
|
}
|
||||||
// Put it in the pool:
|
|
||||||
// The following is roughly like: _sounds[path] = sd;
|
// The following is roughly like: _sounds[path] = sd;
|
||||||
// But, it gives us an iterator into the map.
|
// But, it gives us an iterator into the map.
|
||||||
pair<SoundMap::const_iterator, bool> ib
|
pair<SoundMap::const_iterator, bool> ib =
|
||||||
=_sounds.insert(SoundMap::value_type(path, sd));
|
_sounds.insert(SoundMap::value_type(path, sd));
|
||||||
if (!ib.second) {
|
if (!ib.second) {
|
||||||
// The insert failed.
|
// The insert failed.
|
||||||
audio_debug(" failed map insert of "<<path);
|
audio_debug(" failed map insert of "<<path);
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
return get_null_sound();
|
return get_null_sound();
|
||||||
}
|
}
|
||||||
// Set si, so that we can get a reference to the path
|
// Get a reference to the path for the MilesAudioSound.
|
||||||
// for the MilesAudioSound.
|
SoundMap::const_iterator si = ib.first;
|
||||||
si=ib.first;
|
cache_path = &((*si).first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create an AudioSound from the sound:
|
// Create an AudioSound from the sound:
|
||||||
PT(AudioSound) audioSound = 0;
|
PT(AudioSound) audioSound;
|
||||||
if (sd != (SoundData *)NULL) {
|
if (sd != (SoundData *)NULL) {
|
||||||
most_recently_used((*si).first);
|
nassertr(cache_path != NULL, NULL);
|
||||||
PT(MilesAudioSound) milesAudioSound
|
most_recently_used(cache_path);
|
||||||
=new MilesAudioSound(this, sd, (*si).first);
|
PT(MilesAudioSound) milesAudioSound = new MilesAudioSound(this, sd, path);
|
||||||
nassertr(milesAudioSound, 0);
|
nassertr(milesAudioSound, NULL);
|
||||||
milesAudioSound->set_active(_active);
|
milesAudioSound->set_active(_active);
|
||||||
bool inserted = _sounds_on_loan.insert(milesAudioSound).second;
|
bool inserted = _sounds_on_loan.insert(milesAudioSound).second;
|
||||||
nassertr(inserted, milesAudioSound.p());
|
nassertr(inserted, milesAudioSound.p());
|
||||||
audioSound=milesAudioSound;
|
audioSound = milesAudioSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasMidiSounds |= (file_name.find(".mid")!=string::npos);
|
_hasMidiSounds |= (file_name.find(".mid")!=string::npos);
|
||||||
audio_debug(" returning 0x" << (void*)audioSound);
|
audio_debug(" returning 0x" << (void*)audioSound);
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
return audioSound;
|
return audioSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,17 +460,19 @@ get_sound(const string& file_name, bool) {
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
uncache_sound(const string& file_name) {
|
uncache_sound(const string &file_name) {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
audio_debug("MilesAudioManager::uncache_sound(file_name=\""
|
audio_debug("MilesAudioManager::uncache_sound(file_name=\""
|
||||||
<<file_name<<"\")");
|
<<file_name<<"\")");
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
Filename path = file_name;
|
Filename path = file_name;
|
||||||
|
|
||||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||||
vfs->resolve_filename(path, get_sound_path());
|
vfs->resolve_filename(path, get_sound_path());
|
||||||
|
|
||||||
audio_debug(" path=\""<<path<<"\"");
|
audio_debug(" path=\""<<path<<"\"");
|
||||||
SoundMap::iterator i=_sounds.find(path);
|
SoundMap::iterator i = _sounds.find(path);
|
||||||
if (i != _sounds.end()) {
|
if (i != _sounds.end()) {
|
||||||
assert(_lru.size()>0);
|
assert(_lru.size()>0);
|
||||||
LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
|
LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
|
||||||
@ -400,18 +480,18 @@ uncache_sound(const string& file_name) {
|
|||||||
_lru.erase(lru_i);
|
_lru.erase(lru_i);
|
||||||
_sounds.erase(i);
|
_sounds.erase(i);
|
||||||
}
|
}
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MilesAudioManager::uncache_a_sound
|
// Function: MilesAudioManager::uncache_a_sound
|
||||||
// Access: Public
|
// Access: Private
|
||||||
// Description:
|
// Description: Assumes the lock is already held.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
uncache_a_sound() {
|
uncache_a_sound() {
|
||||||
audio_debug("MilesAudioManager::uncache_a_sound()");
|
audio_debug("MilesAudioManager::uncache_a_sound()");
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
// uncache least recently used:
|
// uncache least recently used:
|
||||||
assert(_lru.size()>0);
|
assert(_lru.size()>0);
|
||||||
LRU::reference path=_lru.front();
|
LRU::reference path=_lru.front();
|
||||||
@ -423,26 +503,26 @@ uncache_a_sound() {
|
|||||||
audio_debug(" uncaching \""<<i->first<<"\"");
|
audio_debug(" uncaching \""<<i->first<<"\"");
|
||||||
_sounds.erase(i);
|
_sounds.erase(i);
|
||||||
}
|
}
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MilesAudioManager::most_recently_used
|
// Function: MilesAudioManager::most_recently_used
|
||||||
// Access: Public
|
// Access: Private
|
||||||
// Description:
|
// Description: Assumes the lock is already held.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
most_recently_used(const string& path) {
|
most_recently_used(const string *path) {
|
||||||
audio_debug("MilesAudioManager::most_recently_used(path=\""
|
audio_debug("MilesAudioManager::most_recently_used(path=\""
|
||||||
<<path<<"\")");
|
<<path<<"\")");
|
||||||
LRU::iterator i=find(_lru.begin(), _lru.end(), &path);
|
LRU::iterator i=find(_lru.begin(), _lru.end(), path);
|
||||||
if (i != _lru.end()) {
|
if (i != _lru.end()) {
|
||||||
_lru.erase(i);
|
_lru.erase(i);
|
||||||
}
|
}
|
||||||
// At this point, path should not exist in the _lru:
|
// At this point, path should not exist in the _lru:
|
||||||
assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
|
assert(find(_lru.begin(), _lru.end(), path) == _lru.end());
|
||||||
_lru.push_back(&path);
|
_lru.push_back(path);
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -452,11 +532,22 @@ most_recently_used(const string& path) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
clear_cache() {
|
clear_cache() {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
do_clear_cache();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MilesAudioManager::do_clear_cache
|
||||||
|
// Access: Private
|
||||||
|
// Description: Assumes the lock is already held.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void MilesAudioManager::
|
||||||
|
do_clear_cache() {
|
||||||
audio_debug("MilesAudioManager::clear_cache()");
|
audio_debug("MilesAudioManager::clear_cache()");
|
||||||
if (_is_valid) { assert(is_valid()); }
|
if (_is_valid) { assert(do_is_valid()); }
|
||||||
_sounds.clear();
|
_sounds.clear();
|
||||||
_lru.clear();
|
_lru.clear();
|
||||||
if (_is_valid) { assert(is_valid()); }
|
if (_is_valid) { assert(do_is_valid()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -466,13 +557,15 @@ clear_cache() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
set_cache_limit(unsigned int count) {
|
set_cache_limit(unsigned int count) {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
|
audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
while (_lru.size() > count) {
|
while (_lru.size() > count) {
|
||||||
uncache_a_sound();
|
uncache_a_sound();
|
||||||
}
|
}
|
||||||
_cache_limit=count;
|
_cache_limit=count;
|
||||||
assert(is_valid());
|
assert(do_is_valid());
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -482,6 +575,8 @@ set_cache_limit(unsigned int count) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
unsigned int MilesAudioManager::
|
unsigned int MilesAudioManager::
|
||||||
get_cache_limit() const {
|
get_cache_limit() const {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
audio_debug("MilesAudioManager::get_cache_limit() returning "
|
audio_debug("MilesAudioManager::get_cache_limit() returning "
|
||||||
<<_cache_limit);
|
<<_cache_limit);
|
||||||
return _cache_limit;
|
return _cache_limit;
|
||||||
@ -494,6 +589,8 @@ get_cache_limit() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
release_sound(MilesAudioSound* audioSound) {
|
release_sound(MilesAudioSound* audioSound) {
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
audio_debug("MilesAudioManager::release_sound(audioSound=\""
|
audio_debug("MilesAudioManager::release_sound(audioSound=\""
|
||||||
<<audioSound->get_name()<<"\"), this = " << (void *)this);
|
<<audioSound->get_name()<<"\"), this = " << (void *)this);
|
||||||
AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
|
AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
|
||||||
@ -766,6 +863,9 @@ force_midi_reset() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MilesAudioManager::
|
void MilesAudioManager::
|
||||||
cleanup() {
|
cleanup() {
|
||||||
|
{
|
||||||
|
MutexHolder holder(_lock);
|
||||||
|
|
||||||
audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
|
audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
|
||||||
<< ", _cleanup_required = " << _cleanup_required);
|
<< ", _cleanup_required = " << _cleanup_required);
|
||||||
if (!_cleanup_required) {
|
if (!_cleanup_required) {
|
||||||
@ -778,7 +878,25 @@ cleanup() {
|
|||||||
(*ai)->cleanup();
|
(*ai)->cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_cache();
|
do_clear_cache();
|
||||||
|
|
||||||
|
_cleanup_required = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivate();
|
||||||
|
|
||||||
|
audio_debug("MilesAudioManager::cleanup() finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MilesAudioManager::deactivate
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Deactivates one manager. Grabs the static lock.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void MilesAudioManager::
|
||||||
|
deactivate() {
|
||||||
|
MutexHolder st_holder(*_static_lock);
|
||||||
|
|
||||||
nassertv(_active_managers > 0);
|
nassertv(_active_managers > 0);
|
||||||
--_active_managers;
|
--_active_managers;
|
||||||
audio_debug(" _active_managers="<<_active_managers);
|
audio_debug(" _active_managers="<<_active_managers);
|
||||||
@ -798,8 +916,6 @@ cleanup() {
|
|||||||
_miles_active = false;
|
_miles_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_cleanup_required = false;
|
|
||||||
audio_debug("MilesAudioManager::cleanup() finished");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "pset.h"
|
#include "pset.h"
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
#include "pdeque.h"
|
#include "pdeque.h"
|
||||||
|
#include "pmutex.h"
|
||||||
|
|
||||||
class MilesAudioSound;
|
class MilesAudioSound;
|
||||||
|
|
||||||
@ -65,6 +66,8 @@ public:
|
|||||||
void stop_all_sounds();
|
void stop_all_sounds();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Mutex _lock; // Protects all the members of this class.
|
||||||
|
|
||||||
// The sound cache:
|
// The sound cache:
|
||||||
class SoundData : public ReferenceCount {
|
class SoundData : public ReferenceCount {
|
||||||
public:
|
public:
|
||||||
@ -82,16 +85,16 @@ private:
|
|||||||
typedef pmap<string, PT(SoundData) > SoundMap;
|
typedef pmap<string, PT(SoundData) > SoundMap;
|
||||||
SoundMap _sounds;
|
SoundMap _sounds;
|
||||||
|
|
||||||
typedef pset<MilesAudioSound* > AudioSet;
|
typedef pset<MilesAudioSound *> AudioSet;
|
||||||
// The offspring of this manager:
|
// The offspring of this manager:
|
||||||
AudioSet _sounds_on_loan;
|
AudioSet _sounds_on_loan;
|
||||||
|
|
||||||
typedef pset<MilesAudioSound* > SoundsPlaying;
|
typedef pset<MilesAudioSound *> SoundsPlaying;
|
||||||
// The sounds from this manager that are currently playing:
|
// The sounds from this manager that are currently playing:
|
||||||
SoundsPlaying _sounds_playing;
|
SoundsPlaying _sounds_playing;
|
||||||
|
|
||||||
// The Least Recently Used mechanism:
|
// The Least Recently Used mechanism:
|
||||||
typedef pdeque<const string* > LRU;
|
typedef pdeque<const string *> LRU;
|
||||||
LRU _lru;
|
LRU _lru;
|
||||||
// State:
|
// State:
|
||||||
float _volume;
|
float _volume;
|
||||||
@ -99,25 +102,35 @@ private:
|
|||||||
bool _active;
|
bool _active;
|
||||||
int _cache_limit;
|
int _cache_limit;
|
||||||
bool _cleanup_required;
|
bool _cleanup_required;
|
||||||
// keep a count for startup and shutdown:
|
|
||||||
static int _active_managers;
|
|
||||||
static bool _miles_active;
|
|
||||||
unsigned int _concurrent_sound_limit;
|
unsigned int _concurrent_sound_limit;
|
||||||
|
|
||||||
bool _is_valid;
|
bool _is_valid;
|
||||||
bool _hasMidiSounds;
|
bool _hasMidiSounds;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Static members. Protected by the following lock.
|
||||||
|
static Mutex *_static_lock;
|
||||||
|
|
||||||
|
// keep a count for startup and shutdown:
|
||||||
|
static int _active_managers;
|
||||||
|
static bool _miles_active;
|
||||||
|
|
||||||
// Optional Downloadable Sound field for software midi
|
// Optional Downloadable Sound field for software midi
|
||||||
static HDLSFILEID _dls_field;
|
static HDLSFILEID _dls_field;
|
||||||
|
|
||||||
typedef pset<MilesAudioManager *> Managers;
|
typedef pset<MilesAudioManager *> Managers;
|
||||||
static Managers *_managers;
|
static Managers *_managers;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool do_is_valid();
|
||||||
|
void do_clear_cache();
|
||||||
|
|
||||||
PT(SoundData) load(Filename file_name);
|
PT(SoundData) load(Filename file_name);
|
||||||
// Tell the manager that the sound dtor was called.
|
// Tell the manager that the sound dtor was called.
|
||||||
void release_sound(MilesAudioSound* audioSound);
|
void release_sound(MilesAudioSound* audioSound);
|
||||||
|
|
||||||
void most_recently_used(const string& path);
|
void most_recently_used(const string *path);
|
||||||
void uncache_a_sound();
|
void uncache_a_sound();
|
||||||
|
|
||||||
void starting_sound(MilesAudioSound* audio);
|
void starting_sound(MilesAudioSound* audio);
|
||||||
@ -133,6 +146,7 @@ private:
|
|||||||
|
|
||||||
void force_midi_reset();
|
void force_midi_reset();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
static void deactivate();
|
||||||
|
|
||||||
friend class MilesAudioSound;
|
friend class MilesAudioSound;
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ private:
|
|||||||
// itwas set inactive.
|
// itwas set inactive.
|
||||||
bool _paused;
|
bool _paused;
|
||||||
|
|
||||||
MilesAudioSound(MilesAudioManager* manager, MilesAudioManager::SoundData *sd,
|
MilesAudioSound(MilesAudioManager *manager, MilesAudioManager::SoundData *sd,
|
||||||
string file_name, float length=0.0f);
|
string file_name, float length=0.0f);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ find_task(AsyncTask *task) const {
|
|||||||
void AsyncTaskManager::
|
void AsyncTaskManager::
|
||||||
service_one_task(AsyncTaskManager::AsyncTaskManagerThread *thread) {
|
service_one_task(AsyncTaskManager::AsyncTaskManagerThread *thread) {
|
||||||
if (!_active.empty()) {
|
if (!_active.empty()) {
|
||||||
AsyncTask *task = _active.front();
|
PT(AsyncTask) task = _active.front();
|
||||||
_active.pop_front();
|
_active.pop_front();
|
||||||
thread->_servicing = task;
|
thread->_servicing = task;
|
||||||
|
|
||||||
@ -375,6 +375,7 @@ void AsyncTaskManager::
|
|||||||
task_done(AsyncTask *task) {
|
task_done(AsyncTask *task) {
|
||||||
task->_state = AsyncTask::S_inactive;
|
task->_state = AsyncTask::S_inactive;
|
||||||
task->_manager = NULL;
|
task->_manager = NULL;
|
||||||
|
--_num_tasks;
|
||||||
|
|
||||||
if (!task->_done_event.empty()) {
|
if (!task->_done_event.empty()) {
|
||||||
PT_Event event = new Event(task->_done_event);
|
PT_Event event = new Event(task->_done_event);
|
||||||
|
@ -40,7 +40,7 @@ ConfigureFn(config_event) {
|
|||||||
EventStoreDouble::init_type("EventStoreDouble");
|
EventStoreDouble::init_type("EventStoreDouble");
|
||||||
EventStoreString::init_type("EventStoreString");
|
EventStoreString::init_type("EventStoreString");
|
||||||
EventStoreWstring::init_type("EventStoreWstring");
|
EventStoreWstring::init_type("EventStoreWstring");
|
||||||
EventStoreTypedRefCount::init_type("EventStoreTypedRefCount");
|
EventStoreTypedRefCount::init_type();
|
||||||
|
|
||||||
ButtonEventList::register_with_read_factory();
|
ButtonEventList::register_with_read_factory();
|
||||||
EventStoreInt::register_with_read_factory();
|
EventStoreInt::register_with_read_factory();
|
||||||
|
@ -47,6 +47,24 @@ EventParameter() {
|
|||||||
INLINE EventParameter::
|
INLINE EventParameter::
|
||||||
EventParameter(const TypedWritableReferenceCount *ptr) : _ptr((TypedWritableReferenceCount *)ptr) { }
|
EventParameter(const TypedWritableReferenceCount *ptr) : _ptr((TypedWritableReferenceCount *)ptr) { }
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventParameter::Pointer constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description: Defines an EventParameter that stores a pointer to
|
||||||
|
// a TypedReferenceCount object. Note that a
|
||||||
|
// TypedReferenceCount is not the same kind of pointer
|
||||||
|
// as a TypedWritableReferenceCount, hence we require
|
||||||
|
// both constructors.
|
||||||
|
//
|
||||||
|
// This accepts a const pointer, even though it stores
|
||||||
|
// (and eventually returns) a non-const pointer. This
|
||||||
|
// is just the simplest way to allow both const and
|
||||||
|
// non-const pointers to be stored, but it does lose the
|
||||||
|
// constness. Be careful.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE EventParameter::
|
||||||
|
EventParameter(const TypedReferenceCount *ptr) : _ptr(new EventStoreTypedRefCount((TypedReferenceCount *)ptr)) { }
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EventParameter::Integer constructor
|
// Function: EventParameter::Integer constructor
|
||||||
@ -236,6 +254,36 @@ get_wstring_value() const {
|
|||||||
return ((const EventStoreWstring *)_ptr.p())->get_value();
|
return ((const EventStoreWstring *)_ptr.p())->get_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventParameter::is_typed_ref_count
|
||||||
|
// Access: Public
|
||||||
|
// Description: Returns true if the EventParameter stores a
|
||||||
|
// TypedReferenceCount pointer, false otherwise. Note
|
||||||
|
// that a TypedReferenceCount is not exactly the same
|
||||||
|
// kind of pointer as a TypedWritableReferenceCount,
|
||||||
|
// hence the need for this separate call.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE bool EventParameter::
|
||||||
|
is_typed_ref_count() const {
|
||||||
|
if (is_empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _ptr->is_of_type(EventStoreTypedRefCount::get_class_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventParameter::get_typed_ref_count_value
|
||||||
|
// Access: Public
|
||||||
|
// Description: Retrieves the value stored in the EventParameter. It
|
||||||
|
// is only valid to call this if is_typed_ref_count()
|
||||||
|
// has already returned true.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TypedReferenceCount *EventParameter::
|
||||||
|
get_typed_ref_count_value() const {
|
||||||
|
nassertr(is_typed_ref_count(), NULL);
|
||||||
|
return ((const EventStoreTypedRefCount *)_ptr.p())->get_value();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EventParameter::get_ptr
|
// Function: EventParameter::get_ptr
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -275,6 +323,40 @@ INLINE EventStoreValueBase::
|
|||||||
~EventStoreValueBase() {
|
~EventStoreValueBase() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventStoreTypedRefCount::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE EventStoreTypedRefCount::
|
||||||
|
EventStoreTypedRefCount(const TypedReferenceCount *value) :
|
||||||
|
_value((TypedReferenceCount *)value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventStoreTypedRefCount::set_value
|
||||||
|
// Access: Public
|
||||||
|
// Description: Changes the value stored in the parameter. It is
|
||||||
|
// dangerous to do this for a parameter already added to
|
||||||
|
// an event, since the parameters may be shared.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void EventStoreTypedRefCount::
|
||||||
|
set_value(const TypedReferenceCount *value) {
|
||||||
|
_value = (TypedReferenceCount *)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventStoreTypedRefCount::get_value
|
||||||
|
// Access: Public
|
||||||
|
// Description: Retrieves the value stored in the parameter.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE TypedReferenceCount *EventStoreTypedRefCount::
|
||||||
|
get_value() const {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EventStoreValue::Default Constructor
|
// Function: EventStoreValue::Default Constructor
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -25,59 +25,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
TypeHandle EventStoreValueBase::_type_handle;
|
TypeHandle EventStoreValueBase::_type_handle;
|
||||||
|
TypeHandle EventStoreTypedRefCount::_type_handle;
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: EventParameter::Pointer constructor
|
|
||||||
// Access: Public
|
|
||||||
// Description: Defines an EventParameter that stores a pointer to
|
|
||||||
// a TypedReferenceCount object. Note that a
|
|
||||||
// TypedReferenceCount is not the same kind of pointer
|
|
||||||
// as a TypedWritableReferenceCount, hence we require
|
|
||||||
// both constructors.
|
|
||||||
//
|
|
||||||
// This accepts a const pointer, even though it stores
|
|
||||||
// (and eventually returns) a non-const pointer. This
|
|
||||||
// is just the simplest way to allow both const and
|
|
||||||
// non-const pointers to be stored, but it does lose the
|
|
||||||
// constness. Be careful.
|
|
||||||
//
|
|
||||||
// This constructor, and the accessors for this type of
|
|
||||||
// event parameter, are declared non-inline so we don't
|
|
||||||
// have to worry about exporting this template class
|
|
||||||
// from this DLL.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
EventParameter::
|
|
||||||
EventParameter(const TypedReferenceCount *ptr) : _ptr(new EventStoreTypedRefCount((TypedReferenceCount *)ptr)) { }
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: EventParameter::is_typed_ref_count
|
|
||||||
// Access: Public
|
|
||||||
// Description: Returns true if the EventParameter stores a
|
|
||||||
// TypedReferenceCount pointer, false otherwise. Note
|
|
||||||
// that a TypedReferenceCount is not exactly the same
|
|
||||||
// kind of pointer as a TypedWritableReferenceCount,
|
|
||||||
// hence the need for this separate call.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
bool EventParameter::
|
|
||||||
is_typed_ref_count() const {
|
|
||||||
if (is_empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _ptr->is_of_type(EventStoreTypedRefCount::get_class_type());
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: EventParameter::get_typed_ref_count_value
|
|
||||||
// Access: Public
|
|
||||||
// Description: Retrieves the value stored in the EventParameter. It
|
|
||||||
// is only valid to call this if is_typed_ref_count()
|
|
||||||
// has already returned true.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
TypedReferenceCount *EventParameter::
|
|
||||||
get_typed_ref_count_value() const {
|
|
||||||
nassertr(is_typed_ref_count(), NULL);
|
|
||||||
return ((const EventStoreTypedRefCount *)_ptr.p())->get_value();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: EventParameter::output
|
// Function: EventParameter::output
|
||||||
@ -98,3 +46,18 @@ output(ostream &out) const {
|
|||||||
out << _ptr->get_type();
|
out << _ptr->get_type();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: EventStoreTypedRefCount::output
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void EventStoreTypedRefCount::
|
||||||
|
output(ostream &out) const {
|
||||||
|
if (_value == (TypedReferenceCount *)NULL) {
|
||||||
|
out << "(empty)";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
out << _value->get_type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@ class EXPCL_PANDA EventParameter {
|
|||||||
PUBLISHED:
|
PUBLISHED:
|
||||||
INLINE EventParameter();
|
INLINE EventParameter();
|
||||||
INLINE EventParameter(const TypedWritableReferenceCount *ptr);
|
INLINE EventParameter(const TypedWritableReferenceCount *ptr);
|
||||||
EventParameter(const TypedReferenceCount *ptr);
|
INLINE EventParameter(const TypedReferenceCount *ptr);
|
||||||
INLINE EventParameter(int value);
|
INLINE EventParameter(int value);
|
||||||
INLINE EventParameter(double value);
|
INLINE EventParameter(double value);
|
||||||
INLINE EventParameter(const string &value);
|
INLINE EventParameter(const string &value);
|
||||||
@ -68,8 +68,8 @@ PUBLISHED:
|
|||||||
INLINE bool is_wstring() const;
|
INLINE bool is_wstring() const;
|
||||||
INLINE wstring get_wstring_value() const;
|
INLINE wstring get_wstring_value() const;
|
||||||
|
|
||||||
bool is_typed_ref_count() const;
|
INLINE bool is_typed_ref_count() const;
|
||||||
TypedReferenceCount *get_typed_ref_count_value() const;
|
INLINE TypedReferenceCount *get_typed_ref_count_value() const;
|
||||||
|
|
||||||
INLINE TypedWritableReferenceCount *get_ptr() const;
|
INLINE TypedWritableReferenceCount *get_ptr() const;
|
||||||
|
|
||||||
@ -111,6 +111,41 @@ private:
|
|||||||
static TypeHandle _type_handle;
|
static TypeHandle _type_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : EventStoreTypedRefCount
|
||||||
|
// Description : A class object for storing specifically objects of
|
||||||
|
// type TypedReferenceCount, which is different than
|
||||||
|
// TypedWritableReferenceCount.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class EXPCL_PANDA EventStoreTypedRefCount : public EventStoreValueBase {
|
||||||
|
public:
|
||||||
|
INLINE EventStoreTypedRefCount(const TypedReferenceCount *value);
|
||||||
|
|
||||||
|
INLINE void set_value(const TypedReferenceCount *value);
|
||||||
|
INLINE TypedReferenceCount *get_value() const;
|
||||||
|
|
||||||
|
virtual void output(ostream &out) const;
|
||||||
|
|
||||||
|
PT(TypedReferenceCount) _value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual TypeHandle get_type() const {
|
||||||
|
return get_class_type();
|
||||||
|
}
|
||||||
|
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||||
|
static TypeHandle get_class_type() {
|
||||||
|
return _type_handle;
|
||||||
|
}
|
||||||
|
static void init_type() {
|
||||||
|
EventStoreValueBase::init_type();
|
||||||
|
register_type(_type_handle, "EventStoreTypedRefCount",
|
||||||
|
EventStoreValueBase::get_class_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TypeHandle _type_handle;
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Class : EventStoreValue
|
// Class : EventStoreValue
|
||||||
// Description : A handy class object for storing simple values (like
|
// Description : A handy class object for storing simple values (like
|
||||||
@ -174,7 +209,6 @@ typedef EventStoreValue<int> EventStoreInt;
|
|||||||
typedef EventStoreValue<double> EventStoreDouble;
|
typedef EventStoreValue<double> EventStoreDouble;
|
||||||
typedef EventStoreValue<string> EventStoreString;
|
typedef EventStoreValue<string> EventStoreString;
|
||||||
typedef EventStoreValue<wstring> EventStoreWstring;
|
typedef EventStoreValue<wstring> EventStoreWstring;
|
||||||
typedef EventStoreValue< PT(TypedReferenceCount) > EventStoreTypedRefCount;
|
|
||||||
|
|
||||||
#include "eventParameter.I"
|
#include "eventParameter.I"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user