diff --git a/panda/src/audio/audio_linux_traits.cxx b/panda/src/audio/audio_linux_traits.cxx index bfa52f9472..01b1d21521 100644 --- a/panda/src/audio/audio_linux_traits.cxx +++ b/panda/src/audio/audio_linux_traits.cxx @@ -29,6 +29,7 @@ static byte* scratch_buffer; static byte* fetch_buffer; static int want_buffers = 0, have_buffers = 0; static bool initializing = true; +static bool stop_mixing = false; static int output_fd; static thread* update_thread; static int sample_size = sizeof(short); @@ -158,35 +159,35 @@ static void update_linux(void) { } } -static void internal_update(void*) { +static void* internal_update(void*) { if ((output_fd = open(audio_device->c_str(), O_WRONLY, 0)) == -1) { audio_cat->error() << "could not open '" << audio_device << "'" << endl; - return; + return (void*)0L; } // this one I don't know about int fragsize = 0x0004000c; if (ioctl(output_fd, SNDCTL_DSP_SETFRAGMENT, &fragsize) == -1) { audio_cat->error() << "faied to set fragment size" << endl; - return; + return (void*)0L; } // for now signed, 16-bit, little endian int format = AFMT_S16_LE; if (ioctl(output_fd, SNDCTL_DSP_SETFMT, &format) == -1) { audio_cat->error() << "failed to set format on the dsp" << endl; - return; + return (void*)0L; } // set stereo int stereo = 1; if (ioctl(output_fd, SNDCTL_DSP_STEREO, &stereo) == -1) { audio_cat->error() << "failed to set stereo on the dsp" << endl; - return; + return (void*)0L; } // set the frequency if (ioctl(output_fd, SNDCTL_DSP_SPEED, &audio_mix_freq) == -1) { audio_cat->error() << "failed to set frequency on the dsp" << endl; - return; + return (void*)0L; } - while (1) { + while (!stop_mixing) { if (have_buffers == 0) { ipc_traits::sleep(0, audio_auto_update_delay); } else { @@ -199,6 +200,20 @@ static void internal_update(void*) { } } } + delete [] buffer1; + delete [] buffer2; + delete [] scratch_buffer; + delete [] fetch_buffer; + delete [] zero_buffer; + stop_mixing = false; + audio_cat->debug() << "exiting internal thread" << endl; + return (void*)0L; +} + +static void shutdown_linux(void) { + stop_mixing = true; + while (stop_mixing); + audio_cat->debug() << "I believe the internal thread has exited" << endl; } static void initialize(void) { @@ -220,12 +235,14 @@ static void initialize(void) { want_buffers = 2; have_buffers = 0; initializing = true; + stop_mixing = false; audio_cat->info() << "spawning internal update thread" << endl; update_thread = thread::create(internal_update, (void*)0L, thread::PRIORITY_NORMAL); AudioManager::set_update_func(update_linux); + AudioManager::set_shutdown_func(shutdown_linux); have_initialized = true; } diff --git a/panda/src/audio/audio_manager.I b/panda/src/audio/audio_manager.I index 4c55dfb3f9..5721139ef6 100644 --- a/panda/src/audio/audio_manager.I +++ b/panda/src/audio/audio_manager.I @@ -41,6 +41,15 @@ INLINE void AudioManager::spawn_update(void) { get_ptr()->ns_spawn_update(); } +//////////////////////////////////////////////////////////////////// +// Function: AudioManager::shutdown +// Access: Public, Static +// Description: kill any internal threads, free any internal data +//////////////////////////////////////////////////////////////////// +INLINE void AudioManager::shutdown(void) { + get_ptr()->ns_shutdown(); +} + //////////////////////////////////////////////////////////////////// // Function: AudioManager::set_volume (sample) // Access: Public, Static @@ -66,4 +75,4 @@ INLINE void AudioManager::set_volume(AudioMusic* music, int v) { // directly; there's only supposed to be one AudioManager // in the universe and it constructs itself. //////////////////////////////////////////////////////////////////// -INLINE AudioManager::AudioManager(void) : _spawned((thread*)0L) {} +INLINE AudioManager::AudioManager(void) {} diff --git a/panda/src/audio/audio_manager.cxx b/panda/src/audio/audio_manager.cxx index afa307269c..6851d4c00e 100644 --- a/panda/src/audio/audio_manager.cxx +++ b/panda/src/audio/audio_manager.cxx @@ -9,7 +9,11 @@ AudioManager* AudioManager::_global_ptr = (AudioManager*)0L; AudioManager::UpdateFunc* AudioManager::_update_func = (AudioManager::UpdateFunc*)0L; +AudioManager::ShutdownFunc* AudioManager::_shutdown_func = + (AudioManager::ShutdownFunc*)0L; mutex AudioManager::_manager_mutex; +bool* AudioManager::_quit = (bool*)0L; +thread* AudioManager::_spawned = (thread*)0L; //////////////////////////////////////////////////////////////////// // Function: AudioManager::set_update_func @@ -24,6 +28,21 @@ void AudioManager::set_update_func(AudioManager::UpdateFunc* func) { _update_func = func; } +//////////////////////////////////////////////////////////////////// +// Function: AudioManager::set_shutdown_func +// Access: Public, Static +// Description: register a function that will shutdown the internal +// audio state +//////////////////////////////////////////////////////////////////// +void AudioManager::set_shutdown_func(AudioManager::ShutdownFunc* func) { + if (_shutdown_func != (AudioManager::ShutdownFunc*)0L) + audio_cat->error() << "There maybe be more then one audio driver installed" + << endl; + _shutdown_func = func; + if (_quit == (bool*)0L) + _quit = new bool(false); +} + //////////////////////////////////////////////////////////////////// // Function: AudioManager::get_ptr // Access: Private, Static @@ -59,11 +78,15 @@ void AudioManager::ns_play(AudioMusic* music) { // Access: static // Description: the thread function to call update forever. //////////////////////////////////////////////////////////////////// -void AudioManager::spawned_update(void*) { - while (1) { +void* AudioManager::spawned_update(void* data) { + bool* flag = (bool*)data; + while (! (*flag)) { AudioManager::update(); ipc_traits::sleep(0, audio_auto_update_delay); } + *flag = false; + audio_cat->debug() << "exiting update thread" << endl; + return (void*)0L; } //////////////////////////////////////////////////////////////////// @@ -90,6 +113,28 @@ void AudioManager::ns_set_volume(AudioMusic* music, int v) { // Description: spawn a thread that calls update every so often //////////////////////////////////////////////////////////////////// void AudioManager::ns_spawn_update(void) { - _spawned = thread::create(spawned_update, (void*)0L, - thread::PRIORITY_NORMAL); + if (_spawned == (thread*)0L) { + if (_quit == (bool*)0L) + _quit = new bool(false); + *_quit = false; + _spawned = thread::create(spawned_update, _quit, thread::PRIORITY_NORMAL); + } else { + audio_cat->error() << "tried to spawn 2 update threads" << endl; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: AudioManager::ns_shutdown +// Access: Private +// Description: non-static implementation of shutdown stuff +//////////////////////////////////////////////////////////////////// +void AudioManager::ns_shutdown(void) { + if (_quit != (bool*)0L) + *_quit = true; + if (_shutdown_func != (ShutdownFunc*)0L) + (*_shutdown_func)(); + if (_spawned != (thread*)0L) + while (*_quit); + audio_cat->debug() << "update thread has shutdown" << endl; + delete _quit; } diff --git a/panda/src/audio/audio_manager.h b/panda/src/audio/audio_manager.h index 7cf6a7c81c..3b596c9b0d 100644 --- a/panda/src/audio/audio_manager.h +++ b/panda/src/audio/audio_manager.h @@ -20,24 +20,30 @@ private: void ns_play(AudioSample*); void ns_play(AudioMusic*); void ns_spawn_update(void); + void ns_shutdown(void); void ns_set_volume(AudioSample*, int); void ns_set_volume(AudioMusic*, int); static AudioManager* get_ptr(void); - static void spawned_update(void*); + static void* spawned_update(void*); typedef void UpdateFunc(void); + typedef void ShutdownFunc(void); static AudioManager* _global_ptr; static UpdateFunc* _update_func; + static ShutdownFunc* _shutdown_func; static mutex _manager_mutex; - thread* _spawned; + static bool* _quit; + static thread* _spawned; public: static void set_update_func(UpdateFunc*); + static void set_shutdown_func(ShutdownFunc*); INLINE static void play(AudioSample*); INLINE static void play(AudioMusic*); INLINE static void update(void); INLINE static void spawn_update(void); + INLINE static void shutdown(void); INLINE static void set_volume(AudioSample*, int); INLINE static void set_volume(AudioMusic*, int); }; diff --git a/panda/src/audio/audio_win_traits.cxx b/panda/src/audio/audio_win_traits.cxx index 9e994e7593..730732a755 100644 --- a/panda/src/audio/audio_win_traits.cxx +++ b/panda/src/audio/audio_win_traits.cxx @@ -657,6 +657,10 @@ void WinMusic::destroy(AudioTraits::MusicClass* music) { WinPlaying::~WinPlaying(void) { } +AudioTraits::PlayingClass::PlayingStatus WinPlaying::status(void) { + return AudioTraits::PlayingClass::BAD; +} + WinPlayer* WinPlayer::_global_instance = (WinPlayer*)0L; WinPlayer::~WinPlayer(void) { diff --git a/panda/src/audio/audio_win_traits.h b/panda/src/audio/audio_win_traits.h index 928e79b425..0ef8e857e7 100644 --- a/panda/src/audio/audio_win_traits.h +++ b/panda/src/audio/audio_win_traits.h @@ -69,6 +69,8 @@ class EXPCL_PANDA WinPlaying : public AudioTraits::PlayingClass { public: INLINE WinPlaying(void); ~WinPlaying(void); + + virtual AudioTraits::PlayingClass::PlayingStatus status(void); }; class EXPCL_PANDA WinPlayer : public AudioTraits::PlayerClass {