mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-17 20:23:47 -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) {
|
if (!_device) {
|
||||||
// this is a unique kind of error
|
// this is a unique kind of error
|
||||||
audio_error("OpenALAudioManager: alcOpenDevice(NULL): ALC couldn't open device");
|
audio_error("OpenALAudioManager: alcOpenDevice(NULL): ALC couldn't open device");
|
||||||
} else {
|
} else {
|
||||||
alcGetError(_device); // clear errors
|
alcGetError(_device); // clear errors
|
||||||
_context=alcCreateContext(_device,NULL);
|
_context=alcCreateContext(_device,NULL);
|
||||||
alc_audio_errcheck("alcCreateContext(_device,NULL)",_device);
|
alc_audio_errcheck("alcCreateContext(_device,NULL)",_device);
|
||||||
if (_context!=NULL) {
|
if (_context!=NULL) {
|
||||||
_openal_active = true;
|
_openal_active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We increment _active_managers regardless of possible errors above.
|
// We increment _active_managers regardless of possible errors above.
|
||||||
// The shutdown call will do the right thing when it's called,
|
// 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_distance_factor(audio_distance_factor);
|
||||||
audio_3d_set_drop_off_factor(audio_drop_off_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
|
// Access: Private
|
||||||
// Description: Returns true if the specified MovieAudio can be
|
// Description: Returns true if the specified MovieAudio should be
|
||||||
// cached into RAM. To be cached, the data must have
|
// cached into RAM. A lot of conditions have to be met
|
||||||
// a filename (otherwise, we have no cache key), and it
|
// in order to allow caching - if any are not met,
|
||||||
// must not take too many bytes.
|
// the file will be streamed.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool OpenALAudioManager::
|
bool OpenALAudioManager::
|
||||||
can_load_audio(MovieAudioCursor *source) {
|
should_load_audio(MovieAudioCursor *source, int mode) {
|
||||||
if (source->get_source()->get_filename().empty()) {
|
if (mode == SM_stream) {
|
||||||
|
// If the user asked for streaming, give him streaming.
|
||||||
return false;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
int channels = source->audio_channels();
|
int channels = source->audio_channels();
|
||||||
int samples = (int)(source->length() * source->audio_rate());
|
int samples = (int)(source->length() * source->audio_rate());
|
||||||
int bytes = samples * channels * 2;
|
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 false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -265,27 +275,31 @@ can_load_audio(MovieAudioCursor *source) {
|
|||||||
// to decrement the client count.
|
// to decrement the client count.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
OpenALAudioManager::SoundData *OpenALAudioManager::
|
OpenALAudioManager::SoundData *OpenALAudioManager::
|
||||||
get_sound_data(MovieAudio *movie) {
|
get_sound_data(MovieAudio *movie, int mode) {
|
||||||
const Filename &path = movie->get_filename();
|
const Filename &path = movie->get_filename();
|
||||||
|
|
||||||
// Search for an already-cached sample or an already-opened stream.
|
// Search for an already-cached sample or an already-opened stream.
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
|
|
||||||
SampleCache::iterator lsmi=_sample_cache.find(path);
|
if (mode != SM_stream) {
|
||||||
if (lsmi != _sample_cache.end()) {
|
SampleCache::iterator lsmi=_sample_cache.find(path);
|
||||||
SoundData *sd = (*lsmi).second;
|
if (lsmi != _sample_cache.end()) {
|
||||||
increment_client_count(sd);
|
SoundData *sd = (*lsmi).second;
|
||||||
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) {
|
|
||||||
increment_client_count(sd);
|
increment_client_count(sd);
|
||||||
return 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();
|
PT(MovieAudioCursor) stream = movie->open();
|
||||||
@ -306,10 +320,12 @@ get_sound_data(MovieAudio *movie) {
|
|||||||
sd->_rate = stream->audio_rate();
|
sd->_rate = stream->audio_rate();
|
||||||
sd->_channels = stream->audio_channels();
|
sd->_channels = stream->audio_channels();
|
||||||
sd->_length = stream->length();
|
sd->_length = stream->length();
|
||||||
|
|
||||||
audio_debug("Creating: " << sd->_movie->get_filename().get_basename());
|
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");
|
audio_debug(path.get_basename() << ": loading as sample");
|
||||||
make_current();
|
make_current();
|
||||||
alGetError(); // clear errors
|
alGetError(); // clear errors
|
||||||
@ -354,7 +370,7 @@ get_sound(MovieAudio *sound, bool positional, int mode) {
|
|||||||
return get_null_sound();
|
return get_null_sound();
|
||||||
}
|
}
|
||||||
PT(OpenALAudioSound) oas =
|
PT(OpenALAudioSound) oas =
|
||||||
new OpenALAudioSound(this, sound, positional);
|
new OpenALAudioSound(this, sound, positional, mode);
|
||||||
|
|
||||||
_all_sounds.insert(oas);
|
_all_sounds.insert(oas);
|
||||||
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)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(MovieAudio) mva = MovieAudio::get(path);
|
||||||
|
|
||||||
PT(OpenALAudioSound) oas =
|
PT(OpenALAudioSound) oas =
|
||||||
new OpenALAudioSound(this, mva, positional);
|
new OpenALAudioSound(this, mva, positional, mode);
|
||||||
|
|
||||||
_all_sounds.insert(oas);
|
_all_sounds.insert(oas);
|
||||||
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
|
PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas;
|
||||||
@ -783,11 +799,11 @@ starting_sound(OpenALAudioSound* audio) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioManager::
|
void OpenALAudioManager::
|
||||||
stopping_sound(OpenALAudioSound* audio) {
|
stopping_sound(OpenALAudioSound* audio) {
|
||||||
_sounds_playing.erase(audio);
|
|
||||||
if (audio->_source) {
|
if (audio->_source) {
|
||||||
_al_sources->insert(audio->_source);
|
_al_sources->insert(audio->_source);
|
||||||
audio->_source = 0;
|
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) {
|
while (limit-- > 0) {
|
||||||
SoundsPlaying::iterator sound = _sounds_playing.begin();
|
SoundsPlaying::iterator sound = _sounds_playing.begin();
|
||||||
assert(sound != _sounds_playing.end());
|
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->push_fresh_buffers();
|
||||||
sound->restart_stalled_audio();
|
sound->restart_stalled_audio();
|
||||||
sound->cache_time(rtc);
|
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);
|
sounds_finished.insert(*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -887,6 +912,8 @@ cleanup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop_all_sounds();
|
||||||
|
|
||||||
AllSounds sounds(_all_sounds);
|
AllSounds sounds(_all_sounds);
|
||||||
AllSounds::iterator ai;
|
AllSounds::iterator ai;
|
||||||
for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
|
for (ai = sounds.begin(); ai != sounds.end(); ++ai) {
|
||||||
|
@ -117,9 +117,9 @@ private:
|
|||||||
void make_current() const;
|
void make_current() const;
|
||||||
|
|
||||||
bool can_use_audio(MovieAudioCursor *source);
|
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.
|
// Tell the manager that the sound dtor was called.
|
||||||
void release_sound(OpenALAudioSound* audioSound);
|
void release_sound(OpenALAudioSound* audioSound);
|
||||||
@ -129,7 +129,7 @@ private:
|
|||||||
|
|
||||||
void starting_sound(OpenALAudioSound* audio);
|
void starting_sound(OpenALAudioSound* audio);
|
||||||
void stopping_sound(OpenALAudioSound* audio);
|
void stopping_sound(OpenALAudioSound* audio);
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -57,7 +57,7 @@ get_calibrated_clock(double rtc) const {
|
|||||||
void OpenALAudioSound::
|
void OpenALAudioSound::
|
||||||
require_sound_data() {
|
require_sound_data() {
|
||||||
if (_sd==0) {
|
if (_sd==0) {
|
||||||
_sd = _manager->get_sound_data(_movie);
|
_sd = _manager->get_sound_data(_movie, _desired_mode);
|
||||||
if (_sd==0) {
|
if (_sd==0) {
|
||||||
audio_error("Could not open audio " << _movie->get_filename());
|
audio_error("Could not open audio " << _movie->get_filename());
|
||||||
cleanup();
|
cleanup();
|
||||||
|
@ -46,7 +46,8 @@ TypeHandle OpenALAudioSound::_type_handle;
|
|||||||
OpenALAudioSound::
|
OpenALAudioSound::
|
||||||
OpenALAudioSound(OpenALAudioManager* manager,
|
OpenALAudioSound(OpenALAudioManager* manager,
|
||||||
MovieAudio *movie,
|
MovieAudio *movie,
|
||||||
bool positional) :
|
bool positional,
|
||||||
|
int mode) :
|
||||||
_movie(movie),
|
_movie(movie),
|
||||||
_sd(NULL),
|
_sd(NULL),
|
||||||
_loops_completed(0),
|
_loops_completed(0),
|
||||||
@ -63,7 +64,8 @@ OpenALAudioSound(OpenALAudioManager* manager,
|
|||||||
_play_rate(1.0),
|
_play_rate(1.0),
|
||||||
_current_time(0.0),
|
_current_time(0.0),
|
||||||
_active(true),
|
_active(true),
|
||||||
_paused(false)
|
_paused(false),
|
||||||
|
_desired_mode(mode)
|
||||||
{
|
{
|
||||||
_location[0] = 0;
|
_location[0] = 0;
|
||||||
_location[1] = 0;
|
_location[1] = 0;
|
||||||
@ -143,7 +145,7 @@ play() {
|
|||||||
require_sound_data();
|
require_sound_data();
|
||||||
if (_manager == 0) return;
|
if (_manager == 0) return;
|
||||||
_manager->starting_sound(this);
|
_manager->starting_sound(this);
|
||||||
|
|
||||||
if (!_source) {
|
if (!_source) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -408,7 +410,7 @@ read_stream_data(int bytelen, unsigned char *buffer) {
|
|||||||
}
|
}
|
||||||
cursor->read_samples(samples, (PN_int16 *)buffer);
|
cursor->read_samples(samples, (PN_int16 *)buffer);
|
||||||
size_t hval = AddHash::add_hash(0, (PN_uint8*)buffer, samples*channels*2);
|
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;
|
fill += samples;
|
||||||
space -= samples;
|
space -= samples;
|
||||||
buffer += (samples * channels * 2);
|
buffer += (samples * channels * 2);
|
||||||
@ -881,7 +883,7 @@ status() const {
|
|||||||
if (_source==0) {
|
if (_source==0) {
|
||||||
return AudioSound::READY;
|
return AudioSound::READY;
|
||||||
}
|
}
|
||||||
if (_loops_completed >= _playing_loops) {
|
if ((_loops_completed >= _playing_loops)&&(_stream_queued.size()==0)) {
|
||||||
return AudioSound::READY;
|
return AudioSound::READY;
|
||||||
} else {
|
} else {
|
||||||
return AudioSound::PLAYING;
|
return AudioSound::PLAYING;
|
||||||
|
@ -116,7 +116,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
OpenALAudioSound(OpenALAudioManager* manager,
|
OpenALAudioSound(OpenALAudioManager* manager,
|
||||||
MovieAudio *movie,
|
MovieAudio *movie,
|
||||||
bool positional);
|
bool positional,
|
||||||
|
int mode);
|
||||||
INLINE void set_calibrated_clock(double rtc, double t, double playrate);
|
INLINE void set_calibrated_clock(double rtc, double t, double playrate);
|
||||||
INLINE double get_calibrated_clock(double rtc) const;
|
INLINE double get_calibrated_clock(double rtc) const;
|
||||||
void correct_calibrated_clock(double rtc, double t);
|
void correct_calibrated_clock(double rtc, double t);
|
||||||
@ -134,6 +135,8 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void do_stop();
|
||||||
|
|
||||||
PT(MovieAudio) _movie;
|
PT(MovieAudio) _movie;
|
||||||
OpenALAudioManager::SoundData *_sd;
|
OpenALAudioManager::SoundData *_sd;
|
||||||
|
|
||||||
@ -168,6 +171,8 @@ private:
|
|||||||
double _length;
|
double _length;
|
||||||
int _loop_count;
|
int _loop_count;
|
||||||
|
|
||||||
|
int _desired_mode;
|
||||||
|
|
||||||
// The calibrated clock is initialized when the
|
// The calibrated clock is initialized when the
|
||||||
// sound starts playing, and is periodically corrected
|
// sound starts playing, and is periodically corrected
|
||||||
// thereafter.
|
// thereafter.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user