void RageSoundDriver::DecodeThread() { SetupDecodingThread(); while( !m_bShutdownDecodeThread ) { /* Fill each playing sound, round-robin. */ { int iSampleRate = GetSampleRate(); ASSERT_M( iSampleRate > 0, ssprintf("%i", iSampleRate) ); int iUsecs = 1000000*chunksize() / iSampleRate; usleep( iUsecs ); } LockMut( m_Mutex ); // LOG->Trace("begin mix"); for( unsigned i = 0; i < ARRAYLEN(m_Sounds); ++i ) { if( m_Sounds[i].m_State != Sound::PLAYING ) continue; Sound *pSound = &m_Sounds[i]; CHECKPOINT_M("Processing the sound while buffers are available."); while( pSound->m_Buffer.num_writable() ) { int iWrote = GetDataForSound( *pSound ); if( iWrote == RageSoundReader::WOULD_BLOCK ) break; if( iWrote < 0 ) { /* This sound is finishing. */ pSound->m_State = Sound::STOPPING; break; // LOG->Trace("mixer: (#%i) eof (%p)", i, pSound->m_pSound ); } } } // LOG->Trace("end mix"); } }
void RageSound_Generic_Software::DecodeThread() { /* SOUNDMAN will be set once RageSoundManager's ctor returns and * assigns it; we might get here before that happens, though. */ while( !SOUNDMAN && !shutdown_decode_thread ) usleep( 10000 ); SetupDecodingThread(); while( !shutdown_decode_thread ) { /* Fill each playing sound, round-robin. */ usleep( 1000000*chunksize() / GetSampleRate(0) ); LockMut( m_Mutex ); // LOG->Trace("begin mix"); for( unsigned i = 0; i < ARRAYSIZE(sounds); ++i ) { /* The volume can change while the sound is playing; update it. */ if( sounds[i].state == sound::PLAYING || sounds[i].state == sound::STOPPING ) sounds[i].volume = sounds[i].snd->GetVolume(); } /* * If a buffer is low on data, keep filling until it has a reasonable amount. * However, once beyond a certain threshold, clamp the rate at which we fill * it. For example, if the threshold is 4k frames, and we have a 32k frame * buffer, fill the buffer as fast as we can until it reaches 4k frames; but * beyond that point, only fill it at a rate relative to realtime (for example, * at 2x realtime). * * This allows a stream to have a large buffer, for higher reliability, without * causing major CPU bursts when the stream starts or underruns. (Filling 32k * takes more CPU than filling 4k frames, and may cause a gameplay skip.) */ for( unsigned i = 0; i < ARRAYSIZE(sounds); ++i ) { if( sounds[i].state != sound::PLAYING ) continue; sound *pSound = &sounds[i]; CHECKPOINT; int frames_filled = 0; while( pSound->buffer.num_writable() ) { /* If there are more than min_fill_frames available, check for * rate clamping. */ if( pSound->buffer.num_readable()*samples_per_block >= unsigned(min_fill_frames) ) { /* Don't write more than two chunks worth of data in one * iteration. Since we delay for one chunk period per loop, * this means we'll fill at no more than 2x realtime. */ if( frames_filled >= chunksize()*2 ) break; } int wrote = GetDataForSound( *pSound ); if( !wrote ) { /* This sound is finishing. */ pSound->state = sound::STOPPING; break; // LOG->Trace("mixer: (#%i) eof (%p)", i, pSound->snd ); } frames_filled += wrote; } } // LOG->Trace("end mix"); } }