sfxInternal.cpp
Engine/source/sfx/sfxInternal.cpp
Implementation of async sound I/O.
Namespaces:
namespace
Detailed Description
Implementation of async sound I/O.
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/sfxInternal.h" 25#include "sfx/sfxDescription.h" 26#include "core/util/safeDelete.h" 27#include "platform/threads/threadPoolAsyncIO.h" 28 29 30/// @file 31/// Implementation of async sound I/O. 32 33 34//#define DEBUG_SPEW 35 36 37namespace SFXInternal { 38 39 40ThreadSafeRef< SFXUpdateThread> gUpdateThread; 41ThreadSafeRef< SFXBufferProcessList> gBufferUpdateList = new SFXBufferProcessList; 42ThreadSafeDeque< SFXBuffer*> gDeadBufferList; 43 44 45//========================================================================== 46// SFXAsyncStream implementation. 47//========================================================================== 48 49//-------------------------------------------------------------------------- 50 51SFXAsyncStream::SFXAsyncStream( const SFXStreamRef& stream, 52 bool isIncremental, 53 U32 streamPacketLength, 54 U32 numReadAhead, 55 bool isLooping ) 56 : Parent( stream, 57 isIncremental 58 ? streamPacketLength 59 * stream->getFormat().getSamplesPerSecond() 60 * stream->getFormat().getBytesPerSample() // Streamed buffer; read in incremental packets. 61 : stream->getDataLength(), // Non-streamed buffer; read entire stream in one packet. 62 stream->getDataLength() // Read all remaining data in stream. 63 - ( dynamic_cast< IPositionable< U32 >* >( stream.ptr() ) 64 ? dynamic_cast< IPositionable< U32 >* >( stream.ptr() )->getPosition() 65 : 0 ), 66 numReadAhead, 67 isLooping, 68 &THREAD_POOL() ), 69 mReadSilenceAtEnd( false ) 70{ 71} 72 73//-------------------------------------------------------------------------- 74 75void SFXAsyncStream::_onArrival( SFXStreamPacket* const& packet ) 76{ 77 #ifdef DEBUG_SPEW 78 Platform::outputDebugString( "[SFXAsyncStream] Packet arrived" ); 79 #endif 80 81 Parent::_onArrival( packet ); 82 83 // Some buffer may be waiting for this data so trigger 84 // an update. 85 86 if( !mIsStopped ) 87 TriggerUpdate(); 88} 89 90//-------------------------------------------------------------------------- 91 92void SFXAsyncStream::_requestNext() 93{ 94 #ifdef DEBUG_SPEW 95 Platform::outputDebugString( "[SFXAsyncStream] Next packet requested" ); 96 #endif 97 98 if( !mNumRemainingSourceElements && mReadSilenceAtEnd ) 99 { 100 // Push an artificial packet of silence. 101 102 SFXStreamPacket* packet = _newPacket( mPacketSize ); 103 packet->mIndex = mNextPacketIndex; 104 mNextPacketIndex ++; 105 mReadSilenceAtEnd = false; 106 dMemset( packet->data, 0, packet->size ); 107 packet->mIsLast = true; 108 109 _onArrival( packet ); 110 } 111 else 112 Parent::_requestNext(); 113} 114 115//========================================================================== 116// SFXWrapAroundBuffer implementation. 117//========================================================================== 118 119//-------------------------------------------------------------------------- 120 121SFXWrapAroundBuffer::SFXWrapAroundBuffer( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description ) 122 : Parent( stream, description ), 123 mWriteOffset( 0 ) 124{ 125 // Determine the device buffer metrics. 126 127 const U32 maxQueuedPackets = isStreaming() ? SFXAsyncQueue::DEFAULT_STREAM_QUEUE_LENGTH : 1; 128 const U32 packetSize = mAsyncState->mStream->getPacketSize(); 129 130 mBufferSize = maxQueuedPackets * packetSize; 131 132 #ifdef DEBUG_SPEW 133 Platform::outputDebugString( "[SFXWrapAroundBuffer] size=%i, packets=%i", 134 mBufferSize, maxQueuedPackets ); 135 #endif 136 137 // For streaming buffers that are not looping, add a packet of silence to the 138 // source stream. 139 140 if( isStreaming() && !description->mIsLooping ) 141 mAsyncState->mStream->setReadSilenceAtEnd( true ); 142} 143 144//-------------------------------------------------------------------------- 145 146void SFXWrapAroundBuffer::write( SFXStreamPacket* const* packets, U32 num ) 147{ 148 AssertFatal( SFXInternal::isSFXThread(), "SFXWrapAroundBuffer::write() - not on SFX thread" ); 149 150 for( U32 i = 0; i < num; ++ i ) 151 { 152 const SFXStreamPacket* packet = packets[ i ]; 153 154 // Determine where in the buffer to copy the data to. In case we are crossing over 155 // the wrap-around point, we need to copy in two slices. 156 157 U32 offset1 = 0; 158 U32 offset2 = 0; 159 U32 numBytes1 = 0; 160 U32 numBytes2 = 0; 161 162 offset1 = mWriteOffset % mBufferSize; 163 numBytes1 = packet->size; 164 165 if( offset1 + numBytes1 > mBufferSize ) 166 { 167 // Crossing wrap-around point. 168 169 numBytes1 = mBufferSize - offset1; 170 numBytes2 = packet->size - numBytes1; 171 } 172 173 offset2 = offset1 + numBytes1; 174 175 #ifdef DEBUG_SPEW 176 Platform::outputDebugString( "[SFXWrapAroundBuffer] writing %i bytes from packet #%i at %i (stream offset: %i)", 177 numBytes1, packet->mIndex, offset1, mWriteOffset ); 178 #endif 179 180 // Copy the packet data. 181 182 _copyData( offset1, packet->data, numBytes1 ); 183 if( numBytes2 > 0 ) 184 { 185 #ifdef DEBUG_SPEW 186 Platform::outputDebugString( "[SFXWrapAroundBuffer] writing %i more bytes at %i", 187 numBytes2, offset2 ); 188 #endif 189 190 _copyData( offset2, &packet->data[ numBytes1 ], numBytes2 ); 191 } 192 193 dFetchAndAdd( mWriteOffset, packet->size ); 194 195 // Free the packet. 196 197 destructSingle( packet ); 198 } 199} 200 201} // namespace SFXInternal 202