finish callbacks

This commit is contained in:
David Rose 2007-08-02 21:07:02 +00:00
parent 4c6b2a4698
commit de34468d87
10 changed files with 293 additions and 88 deletions

View File

@ -27,3 +27,27 @@ INLINE bool GlobalMilesManager::
is_open() const {
return _is_open;
}
////////////////////////////////////////////////////////////////////
// Function: GlobalMilesManager::get_num_samples
// Access: Public
// Description: Returns the number of sample handles that have been
// allocated.
////////////////////////////////////////////////////////////////////
INLINE int GlobalMilesManager::
get_num_samples() const {
MutexHolder holder(_samples_lock);
return _samples.size();
}
////////////////////////////////////////////////////////////////////
// Function: GlobalMilesManager::get_num_sequences
// Access: Public
// Description: Returns the number of sequence handles that have been
// allocated.
////////////////////////////////////////////////////////////////////
INLINE int GlobalMilesManager::
get_num_sequences() const {
MutexHolder holder(_sequences_lock);
return _sequences.size();
}

View File

@ -25,11 +25,16 @@
#include "mss.h"
#include "pset.h"
#include "pmutex.h"
#include "mutexHolder.h"
#ifndef UINTa
#define UINTa U32
#endif
#ifndef SINTa
#define SINTa S32
#endif
class MilesAudioSample;
class MilesAudioSequence;
@ -51,9 +56,11 @@ public:
bool get_sample(HSAMPLE &sample, size_t &index, MilesAudioSample *sound);
void release_sample(size_t index, MilesAudioSample *sound);
INLINE int get_num_samples() const;
bool get_sequence(HSEQUENCE &sequence, size_t &index, MilesAudioSequence *sound);
void release_sequence(size_t index, MilesAudioSequence *sound);
INLINE int get_num_sequences() const;
void force_midi_reset();

View File

@ -32,6 +32,7 @@
#include "nullAudioSound.h"
#include "string_utils.h"
#include "mutexHolder.h"
#include "reMutexHolder.h"
#include <algorithm>
@ -52,7 +53,9 @@ PT(AudioManager) Create_AudioManager() {
// Miles resources.
////////////////////////////////////////////////////////////////////
MilesAudioManager::
MilesAudioManager() : _streams_lock("MilesAudioManager::_streams_lock"),
MilesAudioManager() :
_lock("MilesAudioManager::_lock"),
_streams_lock("MilesAudioManager::_streams_lock"),
_streams_cvar(_streams_lock)
{
audio_debug("MilesAudioManager::MilesAudioManager(), this = "
@ -68,6 +71,7 @@ MilesAudioManager() : _streams_lock("MilesAudioManager::_streams_lock"),
_concurrent_sound_limit = 0;
_is_valid = true;
_hasMidiSounds = false;
_sounds_finished = false;
// We used to hang a call to a force-shutdown function on atexit(),
// so that any running sounds (particularly MIDI sounds) would be
@ -125,22 +129,8 @@ shutdown() {
////////////////////////////////////////////////////////////////////
bool MilesAudioManager::
is_valid() {
bool check=true;
if (_sounds.size() != _lru.size()) {
audio_debug("-- Error _sounds.size() != _lru.size() --");
check=false;
} else {
LRU::const_iterator i=_lru.begin();
for (; i != _lru.end(); ++i) {
SoundMap::const_iterator smi=_sounds.find(**i);
if (smi == _sounds.end()) {
audio_debug("-- "<<**i<<" in _lru and not in _sounds --");
check=false;
break;
}
}
}
return _is_valid && check;
ReMutexHolder holder(_lock);
return do_is_valid();
}
////////////////////////////////////////////////////////////////////
@ -149,15 +139,15 @@ is_valid() {
// Description:
////////////////////////////////////////////////////////////////////
PT(AudioSound) MilesAudioManager::
get_sound(const string& file_name, bool) {
get_sound(const string &file_name, bool) {
ReMutexHolder holder(_lock);
audio_debug("MilesAudioManager::get_sound(file_name=\""<<file_name<<"\")");
if(!is_valid()) {
if (!do_is_valid()) {
audio_debug("invalid MilesAudioManager returning NullSound");
return get_null_sound();
}
assert(is_valid());
Filename path = file_name;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
@ -172,6 +162,7 @@ get_sound(const string& file_name, bool) {
// ...found the sound in the cache.
sd = (*si).second;
audio_debug(" sound found in pool 0x" << (void*)sd);
} else {
// ...the sound was not found in the cache/pool.
sd = load(path);
@ -183,11 +174,11 @@ get_sound(const string& file_name, bool) {
// The following is roughly like: _sounds[path] = sd;
// But, it gives us an iterator into the map.
pair<SoundMap::const_iterator, bool> ib
=_sounds.insert(SoundMap::value_type(path, sd));
= _sounds.insert(SoundMap::value_type(path, sd));
if (!ib.second) {
// The insert failed.
audio_debug(" failed map insert of "<<path);
assert(is_valid());
nassertr(do_is_valid(), NULL);
return get_null_sound();
}
// Set si, so that we can get a reference to the path
@ -228,7 +219,7 @@ get_sound(const string& file_name, bool) {
}
audio_debug(" returning 0x" << (void*)audioSound);
assert(is_valid());
nassertr(do_is_valid(), NULL);
return audioSound;
}
@ -238,10 +229,11 @@ get_sound(const string& file_name, bool) {
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
uncache_sound(const string& file_name) {
uncache_sound(const string &file_name) {
audio_debug("MilesAudioManager::uncache_sound(file_name=\""
<<file_name<<"\")");
assert(is_valid());
ReMutexHolder holder(_lock);
nassertv(do_is_valid());
Filename path = file_name;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
@ -249,15 +241,15 @@ uncache_sound(const string& file_name) {
vfs->resolve_filename(path, get_model_path());
audio_debug(" path=\""<<path<<"\"");
SoundMap::iterator i=_sounds.find(path);
SoundMap::iterator i = _sounds.find(path);
if (i != _sounds.end()) {
assert(_lru.size()>0);
LRU::iterator lru_i=find(_lru.begin(), _lru.end(), &(i->first));
assert(lru_i != _lru.end());
nassertv(_lru.size() > 0);
LRU::iterator lru_i = find(_lru.begin(), _lru.end(), &(i->first));
nassertv(lru_i != _lru.end());
_lru.erase(lru_i);
_sounds.erase(i);
}
assert(is_valid());
nassertv(do_is_valid());
}
////////////////////////////////////////////////////////////////////
@ -268,10 +260,8 @@ uncache_sound(const string& file_name) {
void MilesAudioManager::
clear_cache() {
audio_debug("MilesAudioManager::clear_cache()");
if (_is_valid) { assert(is_valid()); }
_sounds.clear();
_lru.clear();
if (_is_valid) { assert(is_valid()); }
ReMutexHolder holder(_lock);
do_clear_cache();
}
////////////////////////////////////////////////////////////////////
@ -281,13 +271,15 @@ clear_cache() {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
set_cache_limit(unsigned int count) {
ReMutexHolder holder(_lock);
audio_debug("MilesAudioManager::set_cache_limit(count="<<count<<")");
assert(is_valid());
nassertv(do_is_valid());
while (_lru.size() > count) {
uncache_a_sound();
}
_cache_limit=count;
assert(is_valid());
nassertv(do_is_valid());
}
////////////////////////////////////////////////////////////////////
@ -308,10 +300,11 @@ get_cache_limit() const {
void MilesAudioManager::
set_volume(float volume) {
audio_debug("MilesAudioManager::set_volume(volume="<<volume<<")");
if (_volume!=volume) {
ReMutexHolder holder(_lock);
if (_volume != volume) {
_volume = volume;
// Tell our AudioSounds to adjust:
AudioSet::iterator i=_sounds_on_loan.begin();
AudioSet::iterator i = _sounds_on_loan.begin();
for (; i!=_sounds_on_loan.end(); ++i) {
(*i)->set_volume((*i)->get_volume());
}
@ -336,11 +329,12 @@ get_volume() const {
void MilesAudioManager::
set_play_rate(float play_rate) {
audio_debug("MilesAudioManager::set_play_rate(play_rate="<<play_rate<<")");
if (_play_rate!=play_rate) {
ReMutexHolder holder(_lock);
if (_play_rate != play_rate) {
_play_rate = play_rate;
// Tell our AudioSounds to adjust:
AudioSet::iterator i=_sounds_on_loan.begin();
for (; i!=_sounds_on_loan.end(); ++i) {
AudioSet::iterator i = _sounds_on_loan.begin();
for (; i != _sounds_on_loan.end(); ++i) {
(*i)->set_play_rate((*i)->get_play_rate());
}
}
@ -364,11 +358,12 @@ get_play_rate() const {
void MilesAudioManager::
set_active(bool active) {
audio_debug("MilesAudioManager::set_active(flag="<<active<<")");
if (_active!=active) {
ReMutexHolder holder(_lock);
if (_active != active) {
_active=active;
// Tell our AudioSounds to adjust:
AudioSet::iterator i=_sounds_on_loan.begin();
for (; i!=_sounds_on_loan.end(); ++i) {
AudioSet::iterator i = _sounds_on_loan.begin();
for (; i != _sounds_on_loan.end(); ++i) {
(*i)->set_active(_active);
}
@ -395,8 +390,9 @@ get_active() const {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
set_concurrent_sound_limit(unsigned int limit) {
ReMutexHolder holder(_lock);
_concurrent_sound_limit = limit;
reduce_sounds_playing_to(_concurrent_sound_limit);
do_reduce_sounds_playing_to(_concurrent_sound_limit);
}
////////////////////////////////////////////////////////////////////
@ -411,17 +407,13 @@ get_concurrent_sound_limit() const {
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::reduce_sounds_playing_to
// Access: Private, Virtual
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
reduce_sounds_playing_to(unsigned int count) {
int limit = _sounds_playing.size() - count;
while (limit-- > 0) {
SoundsPlaying::iterator sound = _sounds_playing.begin();
assert(sound != _sounds_playing.end());
(**sound).stop();
}
ReMutexHolder holder(_lock);
do_reduce_sounds_playing_to(count);
}
////////////////////////////////////////////////////////////////////
@ -444,12 +436,33 @@ stop_all_sounds() {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
update() {
MutexHolder holder(_streams_lock);
{
MutexHolder holder(_streams_lock);
if (_stream_thread.is_null() && !_streams.empty()) {
// If we don't have a sub-thread, we have to service the streams
// in the main thread.
do_service_streams();
}
}
if (_stream_thread.is_null() && !_streams.empty()) {
// If we don't have a sub-thread, we have to service the streams
// in the main thread.
do_service_streams();
if (_sounds_finished) {
_sounds_finished = false;
// If the _sounds_finished flag was set, we should scan our list
// of playing sounds and see if any of them have finished
// recently. We don't do this in the finished callback, because
// that might have been called in a sub-thread (and we may not
// have threading supported--and mutex protection--compiled in).
SoundsPlaying::iterator si = _sounds_playing.begin();
while (si != _sounds_playing.end()) {
MilesAudioSound *sound = (*si);
++si;
if (sound->status() == AudioSound::READY) {
sound->stop();
}
}
}
}
@ -462,6 +475,7 @@ void MilesAudioManager::
release_sound(MilesAudioSound *audioSound) {
audio_debug("MilesAudioManager::release_sound(audioSound=\""
<<audioSound->get_name()<<"\"), this = " << (void *)this);
ReMutexHolder holder(_lock);
AudioSet::iterator ai = _sounds_on_loan.find(audioSound);
nassertv(ai != _sounds_on_loan.end());
_sounds_on_loan.erase(ai);
@ -480,6 +494,7 @@ void MilesAudioManager::
cleanup() {
audio_debug("MilesAudioManager::cleanup(), this = " << (void *)this
<< ", _cleanup_required = " << _cleanup_required);
ReMutexHolder holder(_lock);
if (!_cleanup_required) {
return;
}
@ -490,7 +505,7 @@ cleanup() {
(*ai)->cleanup();
}
clear_cache();
do_clear_cache();
// Now stop the thread, if it has been started.
if (!_stream_thread.is_null()) {
@ -519,6 +534,7 @@ cleanup() {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
output(ostream &out) const {
ReMutexHolder holder(_lock);
out << get_type() << ": " << _sounds_playing.size()
<< " / " << _sounds_on_loan.size() << " sounds playing / total";
}
@ -530,15 +546,88 @@ output(ostream &out) const {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
write(ostream &out) const {
ReMutexHolder holder(_lock);
out << (*this) << "\n";
AudioSet::const_iterator ai;
for (ai = _sounds_on_loan.begin(); ai != _sounds_on_loan.end(); ++ai) {
MilesAudioSound *sound = (*ai);
out << " " << *sound << "\n";
}
{
MutexHolder holder(_streams_lock);
out << _streams.size() << " streams opened.\n";
if (!_stream_thread.is_null()) {
out << "(Audio streaming thread has been started.)\n";
}
}
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
int num_samples = mgr->get_num_samples();
out << num_samples << " sample handles allocated globally.\n";
int num_sequences = mgr->get_num_sequences();
out << num_sequences << " sequence handles allocated globally.\n";
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::do_is_valid
// Access: Private
// Description: Implementation of is_valid(). Assumes the lock is
// already held.
////////////////////////////////////////////////////////////////////
bool MilesAudioManager::
do_is_valid() {
bool check = true;
if (_sounds.size() != _lru.size()) {
audio_debug("-- Error _sounds.size() != _lru.size() --");
check = false;
} else {
LRU::const_iterator i = _lru.begin();
for (; i != _lru.end(); ++i) {
SoundMap::const_iterator smi = _sounds.find(**i);
if (smi == _sounds.end()) {
audio_debug("-- "<<**i<<" in _lru and not in _sounds --");
check = false;
break;
}
}
}
return _is_valid && check;
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::do_reduce_sounds_playing_to
// Access: Private
// Description: Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
do_reduce_sounds_playing_to(unsigned int count) {
int limit = _sounds_playing.size() - count;
while (limit-- > 0) {
SoundsPlaying::iterator sound = _sounds_playing.begin();
assert(sound != _sounds_playing.end());
(**sound).stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::do_clear_cache
// Access: Private
// Description: Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
do_clear_cache() {
if (_is_valid) { nassertv(do_is_valid()); }
_sounds.clear();
_lru.clear();
if (_is_valid) { nassertv(do_is_valid()); }
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::start_service_stream
// Access: Private
@ -580,7 +669,7 @@ stop_service_stream(HSTREAM stream) {
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::most_recently_used
// Access: Private
// Description:
// Description: Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
most_recently_used(const string &path) {
@ -593,18 +682,18 @@ most_recently_used(const string &path) {
// At this point, path should not exist in the _lru:
assert(find(_lru.begin(), _lru.end(), &path) == _lru.end());
_lru.push_back(&path);
assert(is_valid());
nassertv(do_is_valid());
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioManager::uncache_a_sound
// Access: Private
// Description:
// Description: Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
uncache_a_sound() {
audio_debug("MilesAudioManager::uncache_a_sound()");
assert(is_valid());
nassertv(do_is_valid());
// uncache least recently used:
assert(_lru.size()>0);
LRU::reference path=_lru.front();
@ -616,7 +705,7 @@ uncache_a_sound() {
audio_debug(" uncaching \""<<i->first<<"\"");
_sounds.erase(i);
}
assert(is_valid());
nassertv(do_is_valid());
}
////////////////////////////////////////////////////////////////////
@ -626,8 +715,9 @@ uncache_a_sound() {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
starting_sound(MilesAudioSound *audio) {
ReMutexHolder holder(_lock);
if (_concurrent_sound_limit) {
reduce_sounds_playing_to(_concurrent_sound_limit);
do_reduce_sounds_playing_to(_concurrent_sound_limit);
}
_sounds_playing.insert(audio);
}
@ -641,6 +731,7 @@ starting_sound(MilesAudioSound *audio) {
////////////////////////////////////////////////////////////////////
void MilesAudioManager::
stopping_sound(MilesAudioSound *audio) {
ReMutexHolder holder(_lock);
_sounds_playing.erase(audio);
if (_hasMidiSounds && _sounds_playing.size() == 0) {
GlobalMilesManager::get_global_ptr()->force_midi_reset();
@ -654,6 +745,8 @@ stopping_sound(MilesAudioSound *audio) {
// Description: Reads a sound file and allocates a SoundData pointer
// for it. Returns NULL if the sound file cannot be
// loaded.
//
// Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
PT(MilesAudioManager::SoundData) MilesAudioManager::
load(const Filename &file_name) {

View File

@ -31,6 +31,7 @@
#include "pvector.h"
#include "thread.h"
#include "pmutex.h"
#include "reMutex.h"
#include "conditionVar.h"
class MilesAudioSound;
@ -65,7 +66,6 @@ public:
virtual unsigned int get_concurrent_sound_limit() const;
virtual void reduce_sounds_playing_to(unsigned int count);
virtual void stop_all_sounds();
virtual void update();
@ -78,6 +78,10 @@ public:
virtual void write(ostream &out) const;
private:
bool do_is_valid();
void do_reduce_sounds_playing_to(unsigned int count);
void do_clear_cache();
void start_service_stream(HSTREAM stream);
void stop_service_stream(HSTREAM stream);
@ -123,12 +127,12 @@ private:
// The offspring of this manager:
AudioSet _sounds_on_loan;
typedef pset<MilesAudioSound* > SoundsPlaying;
typedef pset<MilesAudioSound *> SoundsPlaying;
// The sounds from this manager that are currently playing:
SoundsPlaying _sounds_playing;
// The Least Recently Used mechanism:
typedef pdeque<const string* > LRU;
typedef pdeque<const string *> LRU;
LRU _lru;
// State:
float _volume;
@ -141,6 +145,10 @@ private:
bool _is_valid;
bool _hasMidiSounds;
// This mutex protects everything above.
ReMutex _lock;
bool _sounds_finished;
typedef pvector<HSTREAM> Streams;
PT(StreamThread) _stream_thread;
Streams _streams;

View File

@ -96,6 +96,8 @@ play() {
&_sd->_raw_data[0], _sd->_raw_data.size(),
0);
_original_playback_rate = AIL_sample_playback_rate(_sample);
AIL_set_sample_user_data(_sample, 0, (SINTa)this);
AIL_register_EOS_callback(_sample, finish_callback);
set_volume(_volume);
set_play_rate(_play_rate);
@ -293,6 +295,19 @@ cleanup() {
stop();
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioSample::output
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void MilesAudioSample::
output(ostream &out) const {
out << get_type() << " " << get_name() << " " << status();
if (!_sd.is_null()) {
out << " " << (_sd->_raw_data.size() + 1023) / 1024 << "K";
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioSample::internal_stop
// Access: Private
@ -306,4 +321,20 @@ internal_stop() {
_sample_index = 0;
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioSample::finish_callback
// Access: Private, Static
// Description: This callback is made by Miles (possibly in a
// sub-thread) when the sample finishes.
////////////////////////////////////////////////////////////////////
void AILCALLBACK MilesAudioSample::
finish_callback(HSAMPLE sample) {
MilesAudioSample *self = (MilesAudioSample *)AIL_sample_user_data(sample, 0);
if (milesAudio_cat.is_debug()) {
milesAudio_cat.debug()
<< "finished " << *self << "\n";
}
self->_manager->_sounds_finished = true;
}
#endif //]

View File

@ -56,9 +56,11 @@ public:
virtual AudioSound::SoundStatus status() const;
virtual void cleanup();
virtual void output(ostream &out) const;
private:
void internal_stop();
static void AILCALLBACK finish_callback(HSAMPLE sample);
PT(MilesAudioManager::SoundData) _sd;
HSAMPLE _sample;

View File

@ -92,6 +92,8 @@ play() {
_sequence = 0;
} else {
AIL_init_sequence(_sequence, &_sd->_raw_data[0], 0);
AIL_set_sequence_user_data(_sequence, 0, (SINTa)this);
AIL_register_sequence_callback(_sequence, finish_callback);
set_volume(_volume);
set_play_rate(_play_rate);
@ -296,4 +298,20 @@ internal_stop() {
_sequence_index = 0;
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioSequence::finish_callback
// Access: Private, Static
// Description: This callback is made by Miles (possibly in a
// sub-thread) when the sequence finishes.
////////////////////////////////////////////////////////////////////
void AILCALLBACK MilesAudioSequence::
finish_callback(HSEQUENCE sequence) {
MilesAudioSequence *self = (MilesAudioSequence *)AIL_sequence_user_data(sequence, 0);
if (milesAudio_cat.is_debug()) {
milesAudio_cat.debug()
<< "finished " << *self << "\n";
}
self->_manager->_sounds_finished = true;
}
#endif //]

View File

@ -58,6 +58,7 @@ public:
private:
void internal_stop();
static void AILCALLBACK finish_callback(HSEQUENCE sequence);
PT(MilesAudioManager::SoundData) _sd;
HSEQUENCE _sequence;

View File

@ -77,6 +77,14 @@ play() {
if (_stream == 0) {
GlobalMilesManager *mgr = GlobalMilesManager::get_global_ptr();
_stream = AIL_open_stream(mgr->_digital_driver, _path.c_str(), 0);
if (_stream == 0) {
milesAudio_cat.warning()
<< "Could not play " << _file_name << ": too many open streams\n";
return;
}
AIL_set_stream_user_data(_stream, 0, (SINTa)this);
AIL_register_stream_callback(_stream, finish_callback);
} else {
// We already had the stream open. Keep it open; just restart
// it.
@ -84,29 +92,24 @@ play() {
_manager->stop_service_stream(_stream);
}
if (_stream == 0) {
milesAudio_cat.warning()
<< "Could not play " << _file_name << ": too many open streams\n";
// Start playing:
nassertv(_stream != 0);
HSAMPLE sample = AIL_stream_sample_handle(_stream);
nassertv(sample != 0);
_original_playback_rate = AIL_sample_playback_rate(sample);
set_volume(_volume);
set_play_rate(_play_rate);
AIL_set_stream_loop_count(_stream, _loop_count);
if (miles_audio_panda_threads) {
AIL_auto_service_stream(_stream, 0);
_manager->start_service_stream(_stream);
} else {
// Start playing:
HSAMPLE sample = AIL_stream_sample_handle(_stream);
nassertv(sample != 0);
_original_playback_rate = AIL_sample_playback_rate(sample);
set_volume(_volume);
set_play_rate(_play_rate);
AIL_set_stream_loop_count(_stream, _loop_count);
if (miles_audio_panda_threads) {
AIL_auto_service_stream(_stream, 0);
_manager->start_service_stream(_stream);
} else {
AIL_auto_service_stream(_stream, 1);
}
AIL_start_stream(_stream);
AIL_auto_service_stream(_stream, 1);
}
AIL_start_stream(_stream);
} else {
// In case _loop_count gets set to forever (zero):
@ -295,5 +298,21 @@ cleanup() {
}
}
////////////////////////////////////////////////////////////////////
// Function: MilesAudioStream::finish_callback
// Access: Private, Static
// Description: This callback is made by Miles (possibly in a
// sub-thread) when the stream finishes.
////////////////////////////////////////////////////////////////////
void AILCALLBACK MilesAudioStream::
finish_callback(HSTREAM stream) {
MilesAudioStream *self = (MilesAudioStream *)AIL_stream_user_data(stream, 0);
if (milesAudio_cat.is_debug()) {
milesAudio_cat.debug()
<< "finished " << *self << "\n";
}
self->_manager->_sounds_finished = true;
}
#endif //]

View File

@ -58,6 +58,8 @@ public:
virtual void cleanup();
private:
static void AILCALLBACK finish_callback(HSTREAM stream);
Filename _path;
HSTREAM _stream;
S32 _original_playback_rate;