sfxDevice.cpp
Engine/source/sfx/sfxDevice.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "sfx/sfxDevice.h" 25#include "sfx/sfxBuffer.h" 26#include "sfx/sfxVoice.h" 27#include "sfx/sfxInternal.h" 28#include "core/tAlgorithm.h" 29#include "console/console.h" 30#include "console/consoleTypes.h" 31 32 33//----------------------------------------------------------------------------- 34 35SFXDevice::SFXDevice( const String& name, SFXProvider* provider, bool useHardware, S32 maxBuffers ) 36 : mName( name ), 37 mProvider( provider ), 38 mUseHardware( useHardware ), 39 mMaxBuffers( maxBuffers ), 40 mCaps( 0 ), 41 mStatNumBuffers( 0 ), 42 mStatNumVoices( 0 ), 43 mStatNumBufferBytes( 0 ) 44{ 45 AssertFatal( provider, "We must have a provider pointer on device creation!" ); 46 47 VECTOR_SET_ASSOCIATION( mBuffers ); 48 VECTOR_SET_ASSOCIATION( mVoices ); 49 50 SFXBuffer::smBufferDestroyedSignal.notify( this, &SFXDevice::_removeBuffer ); 51 SFXVoice::smVoiceDestroyedSignal.notify( this, &SFXDevice::_removeVoice ); 52 53 Con::addVariable( "SFX::Device::numBuffers", TypeS32, &mStatNumBuffers ); 54 Con::addVariable( "SFX::Device::numVoices", TypeS32, &mStatNumVoices ); 55 Con::addVariable( "SFX::Device::numBufferBytes", TypeS32, &mStatNumBufferBytes ); 56} 57 58//----------------------------------------------------------------------------- 59 60SFXDevice::~SFXDevice() 61{ 62 Con::removeVariable( "SFX::Device::numBuffers" ); 63 Con::removeVariable( "SFX::Device::numVoices" ); 64 Con::removeVariable( "SFX::Device::numBufferBytes" ); 65 66 _releaseAllResources(); 67} 68 69//----------------------------------------------------------------------------- 70 71void SFXDevice::_releaseAllResources() 72{ 73 using namespace SFXInternal; 74 75 // Kill the update thread, if there is one. 76 // Do this first so that further buffer processing 77 // can be done synchronously by us. 78 79 ThreadSafeRef< SFXUpdateThread> sfxThread = UPDATE_THREAD(); 80 if( sfxThread != NULL ) 81 { 82 gUpdateThread = NULL; // Kill the global reference. 83 84 sfxThread->stop(); 85 sfxThread->triggerUpdate(); 86 sfxThread->join(); 87 88 sfxThread = NULL; 89 } 90 91 // Clean up voices. Do this before cleaning up buffers so that 92 // resources held by voices that are tied to resources held by buffers 93 // get released properly. 94 95 SFXVoice::smVoiceDestroyedSignal.remove( this, &SFXDevice::_removeVoice ); 96 for( VoiceIterator voice = mVoices.begin(); 97 voice != mVoices.end(); voice++ ) 98 ( *voice )->destroySelf(); 99 mVoices.clear(); 100 101 // Clean up buffers. 102 103 SFXBuffer::smBufferDestroyedSignal.remove( this, &SFXDevice::_removeBuffer ); 104 for( BufferIterator buffer = mBuffers.begin(); 105 buffer != mBuffers.end(); ++ buffer ) 106 if( !( *buffer )->isDead() ) 107 ( *buffer )->destroySelf(); 108 mBuffers.clear(); 109 110 // Flush all asynchronous requests. 111 112 THREAD_POOL().flushWorkItems(); 113 114 // Clean out the buffer update list and kill 115 // all buffers that surfaced on the dead list. 116 // Now the sound buffers are really gone. 117 118 UPDATE_LIST().process(); 119 PurgeDeadBuffers(); 120 121 // Clean out stats. 122 123 mStatNumBuffers = 0; 124 mStatNumVoices = 0; 125 mStatNumBufferBytes = 0; 126} 127 128//----------------------------------------------------------------------------- 129 130void SFXDevice::update() 131{ 132 using namespace SFXInternal; 133 134 // If we don't have an update thread, do the 135 // updates now on the main thread. 136 137 if( !UPDATE_THREAD() ) 138 UPDATE_LIST().process( MAIN_THREAD_PROCESS_TIMEOUT ); 139 140 // Clean out buffers that have surfaced on the dead 141 // buffer list. 142 143 PurgeDeadBuffers(); 144} 145 146//----------------------------------------------------------------------------- 147 148void SFXDevice::_addBuffer( SFXBuffer* buffer ) 149{ 150 AssertFatal( buffer, "SFXDevice::_addBuffer() - Got a null buffer!" ); 151 152 // Register the buffer. 153 154 mBuffers.push_back( buffer ); 155 mStatNumBuffers ++; 156 mStatNumBufferBytes += buffer->getMemoryUsed(); 157 158 // Start loading the buffer. 159 160 buffer->load(); 161} 162 163//----------------------------------------------------------------------------- 164 165void SFXDevice::_removeBuffer( SFXBuffer* buffer ) 166{ 167 AssertFatal( buffer, "SFXDevice::_removeBuffer() - Got a null buffer!" ); 168 169 BufferIterator iter = T3D::find( mBuffers.begin(), mBuffers.end(), buffer ); 170 if( iter != mBuffers.end() ) 171 { 172 SFXBuffer* curBuf = *iter; 173 174 mStatNumBufferBytes -= curBuf->getMemoryUsed(); 175 mStatNumBuffers --; 176 177 mBuffers.erase( iter ); 178 } 179} 180 181//----------------------------------------------------------------------------- 182 183void SFXDevice::_addVoice( SFXVoice* voice ) 184{ 185 AssertFatal( voice, "SFXDevice::_addVoice() - Got a null voice!" ); 186 using namespace SFXInternal; 187 188 // Bind the voice to its buffer. This is deferred up to here in order 189 // to only bind voices that have been successfully constructed. 190 191 voice->_attachToBuffer(); 192 193 // Register the voice. 194 195 mVoices.push_back( voice ); 196 mStatNumVoices ++; 197} 198 199//----------------------------------------------------------------------------- 200 201void SFXDevice::_removeVoice( SFXVoice* voice ) 202{ 203 AssertFatal( voice, "SFXDevice::_removeVoice() - Got null voice!" ); 204 205 VoiceIterator iter = T3D::find( mVoices.begin(), mVoices.end(), voice ); 206 if( iter != mVoices.end() ) 207 { 208 mStatNumVoices --; 209 mVoices.erase( iter ); 210 } 211} 212