mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
Fixed several memory management bugs, and added streaming control
This commit is contained in:
parent
16b6c060a8
commit
4a474bfb13
@ -123,14 +123,14 @@ OpenALAudioManager() {
|
||||
if (!_device) {
|
||||
// this is a unique kind of error
|
||||
audio_error("OpenALAudioManager: alcOpenDevice(NULL): ALC couldn't open device");
|
||||
} else {
|
||||
} else {
|
||||
alcGetError(_device); // clear errors
|
||||
_context=alcCreateContext(_device,NULL);
|
||||
alc_audio_errcheck("alcCreateContext(_device,NULL)",_device);
|
||||
if (_context!=NULL) {
|
||||
_openal_active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// We increment _active_managers regardless of possible errors above.
|
||||
// The shutdown call will do the right thing when it's called,
|
||||
@ -151,7 +151,6 @@ OpenALAudioManager() {
|
||||
audio_3d_set_distance_factor(audio_distance_factor);
|
||||
audio_3d_set_drop_off_factor(audio_drop_off_factor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -232,25 +231,36 @@ can_use_audio(MovieAudioCursor *source) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: OpenALAudioManager::can_load_audio
|
||||
// Function: OpenALAudioManager::should_load_audio
|
||||
// Access: Private
|
||||
// Description: Returns true if the specified MovieAudio can be
|
||||
// cached into RAM. To be cached, the data must have
|
||||
// a filename (otherwise, we have no cache key), and it
|
||||
// must not take too many bytes.
|
||||
// Description: Returns true if the specified MovieAudio should be
|
||||
// cached into RAM. A lot of conditions have to be met
|
||||
// in order to allow caching - if any are not met,
|
||||
// the file will be streamed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool OpenALAudioManager::
|
||||
can_load_audio(MovieAudioCursor *source) {
|
||||
if (source->get_source()->get_filename().empty()) {
|
||||
should_load_audio(MovieAudioCursor *source, int mode) {
|
||||
if (mode == SM_stream) {
|
||||
// If the user asked for streaming, give him streaming.
|
||||
return false;
|
||||
}
|
||||
if ((source->length() > 3600.0)||(source->ready() != 0x40000000)) {
|
||||
if (source->get_source()->get_filename().empty()) {
|
||||
// Non-files cannot be preloaded.
|
||||
return false;
|
||||
}
|
||||
if (source->ready() != 0x40000000) {
|
||||
// Streaming sources cannot be preloaded.
|
||||
return false;
|
||||
}
|
||||
if (source->length() > 3600.0) {
|
||||
// Anything longer than an hour cannot be preloaded.
|
||||
return false;
|
||||
}
|
||||
int channels = source->audio_channels();
|
||||
int samples = (int)(source->length() * source->audio_rate());
|
||||
int bytes = samples * channels * 2;
|
||||
if (bytes > audio_preload_threshold) {
|
||||
if ((mode == SM_heuristic)&&(bytes > audio_preload_threshold)) {
|
||||
// In heuristic mode, if file is long, stream it.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -265,27 +275,31 @@ can_load_audio(MovieAudioCursor *source) {
|
||||
// to decrement the client count.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
OpenALAudioManager::SoundData *OpenALAudioManager::
|
||||
get_sound_data(MovieAudio *movie) {
|
||||
get_sound_data(MovieAudio *movie, int mode) {
|
||||
const Filename &path = movie->get_filename();
|
||||
|
||||
// Search for an already-cached sample or an already-opened stream.
|
||||
if (!path.empty()) {
|
||||
|
||||
SampleCache::iterator lsmi=_sample_cache.find(path);
|
||||
if (lsmi != _sample_cache.end()) {
|
||||
SoundData *sd = (*lsmi).second;
|
||||
increment_client_count(sd);
|
||||
return sd;
|
||||
}
|
||||
|
||||
ExpirationQueue::iterator exqi;
|
||||
for (exqi=_expiring_streams.begin(); exqi!=_expiring_streams.end(); exqi++) {
|
||||
SoundData *sd = (SoundData*)(*exqi);
|
||||
if (sd->_movie->get_filename() == path) {
|
||||
if (mode != SM_stream) {
|
||||
SampleCache::iterator lsmi=_sample_cache.find(path);
|
||||
if (lsmi != _sample_cache.end()) {
|
||||
SoundData *sd = (*lsmi).second;
|
||||
increment_client_count(sd);
|
||||
return sd;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != SM_sample) {
|
||||
ExpirationQueue::iterator exqi;
|
||||
for (exqi=_expiring_streams.begin(); exqi!=_expiring_streams.end(); exqi++) {
|
||||
SoundData *sd = (SoundData*)(*exqi);
|
||||
if (sd->_movie->get_filename() == path) {
|
||||
increment_client_count(sd);
|
||||
return sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PT(MovieAudioCursor) stream = movie->open();
|
||||
@ -306,10 +320,12 @@ get_sound_data(MovieAudio *movie) {
|
||||
sd->_rate = stream->audio_rate();
|
||||
sd->_channels = stream->audio_channels();
|
||||
sd->_length = stream->length();
|
||||
|
||||
audio_debug("Creating: " << sd->_movie->get_filename().get_basename());
|
||||
audio_debug(" - Rate: " << sd->_rate);
|
||||
audio_debug(" - Channels: " << sd->_channels);
|
||||
audio_debug(" - Length: " << sd->_length);
|
||||
|
||||
if (can_load_audio(stream)) {
|
||||
if (should_load_audio(stream, mode)) {
|
||||
audio_debug(path.get_basename() << ": loading as sample");
|
||||
make_current();
|
||||
alGetError(); // clear errors
|
||||
@ -354,7 +370,7 @@ get_sound(MovieAudio *sound, bool positional, int mode) {
|
||||
return get_null_sound();
|
||||
}
|
||||
PT(OpenALAudioSound) oas =
|
||||
new OpenALAudioSound(this, sound, positional);
|
||||
new OpenALAudioSound(this, sound, positional, mode);
|
||||
|
||||
_all_sounds.insert(oas);
|
||||
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
|
||||
@ -385,7 +401,7 @@ get_sound(const string &file_name, bool positional, int mode) {
|
||||
PT(MovieAudio) mva = MovieAudio::get(path);
|
||||
|
||||
PT(OpenALAudioSound) oas =
|
||||
new OpenALAudioSound(this, mva, positional);
|
||||
new OpenALAudioSound(this, mva, positional, mode);
|
||||
|
||||
_all_sounds.insert(oas);
|
||||
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
|
||||
@ -783,11 +799,11 @@ starting_sound(OpenALAudioSound* audio) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void OpenALAudioManager::
|
||||
stopping_sound(OpenALAudioSound* audio) {
|
||||
_sounds_playing.erase(audio);
|
||||
if (audio->_source) {
|
||||
_al_sources->insert(audio->_source);
|
||||
audio->_source = 0;
|
||||
}
|
||||
_sounds_playing.erase(audio); // This could cause the sound to destruct.
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -825,7 +841,14 @@ reduce_sounds_playing_to(unsigned int count) {
|
||||
while (limit-- > 0) {
|
||||
SoundsPlaying::iterator sound = _sounds_playing.begin();
|
||||
assert(sound != _sounds_playing.end());
|
||||
(**sound).stop();
|
||||
// When the user stops a sound, there is still a PT in the
|
||||
// user's hand. When we stop a sound here, however,
|
||||
// this can remove the last PT. This can cause an ugly
|
||||
// recursion where stop calls the destructor, and the
|
||||
// destructor calls stop. To avoid this, we create
|
||||
// a temporary PT, stop the sound, and then release the PT.
|
||||
PT(OpenALAudioSound) s = (*sound);
|
||||
s->stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -862,7 +885,9 @@ update() {
|
||||
sound->push_fresh_buffers();
|
||||
sound->restart_stalled_audio();
|
||||
sound->cache_time(rtc);
|
||||
if ((sound->_source == 0)||(sound->_loops_completed >= sound->_playing_loops)) {
|
||||
if ((sound->_source == 0)||
|
||||
((sound->_stream_queued.size() == 0)&&
|
||||
(sound->_loops_completed >= sound->_playing_loops))) {
|
||||
sounds_finished.insert(*i);
|
||||
}
|
||||
}
|
||||
@ -887,6 +912,8 @@ cleanup() {
|
||||
return;
|
||||
}
|
||||
|
||||
stop_all_sounds();
|
||||
|
||||
AllSounds sounds(_all_sounds);
|
||||
AllSounds::iterator ai;
|
||||
for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
|
||||
|
@ -117,9 +117,9 @@ private:
|
||||
void make_current() const;
|
||||
|
||||
bool can_use_audio(MovieAudioCursor *source);
|
||||
bool can_load_audio(MovieAudioCursor *source);
|
||||
bool should_load_audio(MovieAudioCursor *source, int mode);
|
||||
|
||||
SoundData *get_sound_data(MovieAudio *source);
|
||||
SoundData *get_sound_data(MovieAudio *source, int mode);
|
||||
|
||||
// Tell the manager that the sound dtor was called.
|
||||
void release_sound(OpenALAudioSound* audioSound);
|
||||
@ -129,7 +129,7 @@ private:
|
||||
|
||||
void starting_sound(OpenALAudioSound* audio);
|
||||
void stopping_sound(OpenALAudioSound* audio);
|
||||
|
||||
|
||||
void cleanup();
|
||||
|
||||
private:
|
||||
|
@ -57,7 +57,7 @@ get_calibrated_clock(double rtc) const {
|
||||
void OpenALAudioSound::
|
||||
require_sound_data() {
|
||||
if (_sd==0) {
|
||||
_sd = _manager->get_sound_data(_movie);
|
||||
_sd = _manager->get_sound_data(_movie, _desired_mode);
|
||||
if (_sd==0) {
|
||||
audio_error("Could not open audio " << _movie->get_filename());
|
||||
cleanup();
|
||||
|
@ -46,7 +46,8 @@ TypeHandle OpenALAudioSound::_type_handle;
|
||||
OpenALAudioSound::
|
||||
OpenALAudioSound(OpenALAudioManager* manager,
|
||||
MovieAudio *movie,
|
||||
bool positional) :
|
||||
bool positional,
|
||||
int mode) :
|
||||
_movie(movie),
|
||||
_sd(NULL),
|
||||
_loops_completed(0),
|
||||
@ -63,7 +64,8 @@ OpenALAudioSound(OpenALAudioManager* manager,
|
||||
_play_rate(1.0),
|
||||
_current_time(0.0),
|
||||
_active(true),
|
||||
_paused(false)
|
||||
_paused(false),
|
||||
_desired_mode(mode)
|
||||
{
|
||||
_location[0] = 0;
|
||||
_location[1] = 0;
|
||||
@ -143,7 +145,7 @@ play() {
|
||||
require_sound_data();
|
||||
if (_manager == 0) return;
|
||||
_manager->starting_sound(this);
|
||||
|
||||
|
||||
if (!_source) {
|
||||
return;
|
||||
}
|
||||
@ -408,7 +410,7 @@ read_stream_data(int bytelen, unsigned char *buffer) {
|
||||
}
|
||||
cursor->read_samples(samples, (PN_int16 *)buffer);
|
||||
size_t hval = AddHash::add_hash(0, (PN_uint8*)buffer, samples*channels*2);
|
||||
audio_debug("Streaming " << cursor->get_source()->get_filename().get_basename() << " at " << t << " hash " << hval);
|
||||
audio_debug("Streaming " << cursor->get_source()->get_name() << " at " << t << " hash " << hval);
|
||||
fill += samples;
|
||||
space -= samples;
|
||||
buffer += (samples * channels * 2);
|
||||
@ -881,7 +883,7 @@ status() const {
|
||||
if (_source==0) {
|
||||
return AudioSound::READY;
|
||||
}
|
||||
if (_loops_completed >= _playing_loops) {
|
||||
if ((_loops_completed >= _playing_loops)&&(_stream_queued.size()==0)) {
|
||||
return AudioSound::READY;
|
||||
} else {
|
||||
return AudioSound::PLAYING;
|
||||
|
@ -116,7 +116,8 @@ public:
|
||||
private:
|
||||
OpenALAudioSound(OpenALAudioManager* manager,
|
||||
MovieAudio *movie,
|
||||
bool positional);
|
||||
bool positional,
|
||||
int mode);
|
||||
INLINE void set_calibrated_clock(double rtc, double t, double playrate);
|
||||
INLINE double get_calibrated_clock(double rtc) const;
|
||||
void correct_calibrated_clock(double rtc, double t);
|
||||
@ -134,6 +135,8 @@ private:
|
||||
|
||||
private:
|
||||
|
||||
void do_stop();
|
||||
|
||||
PT(MovieAudio) _movie;
|
||||
OpenALAudioManager::SoundData *_sd;
|
||||
|
||||
@ -168,6 +171,8 @@ private:
|
||||
double _length;
|
||||
int _loop_count;
|
||||
|
||||
int _desired_mode;
|
||||
|
||||
// The calibrated clock is initialized when the
|
||||
// sound starts playing, and is periodically corrected
|
||||
// thereafter.
|
||||
|
Loading…
x
Reference in New Issue
Block a user