www.pudn.com > SoundMixer_Example_v1_0.zip > CMixerThread.cpp


   /* 
    * 
============================================================================ 
    *  Name     : CMixerThread.cpp 
    *  Part of  : SoundMixer 
    *  Created  : 03/01/2003 by Forum Nokia 
    *  Description: 
    *     This is the project specification file for SoundMixer. 
    * 
    *  Version  : 1.0.0 
    *  Copyright: Forum Nokia 
    * 
============================================================================ 
    */ 
 
// INCLUDES 
#include "CMixerThread.h" 
#include  
#include "TSample.h" 
#include "TAudioShared.h" 
 
// CONSTANTS 
const TInt KSampleRate = 16000;	                // sample rate used 
const TInt KBufferSize = KSampleRate / 20;	// 20 buffers per second 
 
 
TInt CMixerThread::ThreadFunction( TAny* aData ) 
	{ 
	TAudioShared& shared = *((TAudioShared*)aData); 
 
	// tell client we're alive 
	// signaled off when destroying this thread 
	shared.iAliveMutex.Wait(); 
 
	CMixerThread* mixerThread = CMixerThread::Create( aData ); 
	if( mixerThread == NULL ) 
		{ 
		return KErrGeneral; 
		} 
 
	// if we're still here, activescheduler has been constructed 
	// start wait loop which runs until it's time to end the thread 
	CActiveScheduler::Start(); 
	delete mixerThread; 
 
	// tell owning thread it's safe to exit 
	shared.iAliveMutex.Signal(); 
 
    return KErrNone; 
	} 
 
 
CMixerThread* CMixerThread::Create( TAny* aData ) 
	{ 
	CMixerThread* self = new CMixerThread( aData ); 
	if( self == NULL ) return self; 
	if( self->Construct() != KErrNone ) 
		{ 
		delete self; 
		return NULL; 
		} 
 
	return self; 
	} 
 
TInt CMixerThread::Construct() 
	{ 
	// create cleanup stack 
	iCleanupStack = CTrapCleanup::New(); 
	if( iCleanupStack == NULL ) 
		{ 
		return KErrNoMemory; 
		} 
 
	TInt err = KErrNone; 
	TRAP( err, ConstructL() ); 
 
	return err; 
	} 
 
void CMixerThread::ConstructL() 
	{ 
	// create active scheduler 
	iActiveScheduler = new( ELeave )CActiveScheduler; 
	CActiveScheduler::Install( iActiveScheduler ); 
 
	// sound inits 
	iSet.iChannels = TMdaAudioDataSettings::EChannelsMono; 
	iSet.iSampleRate = TMdaAudioDataSettings::ESampleRate16000Hz; 
	iSet.iVolume = 1; 
 
	iMixBuffer = new( ELeave )TInt[ KBufferSize ]; 
	iBuffer = new( ELeave )TInt16[ KBufferSize ]; 
 
	iBufferPtr.Set( TPtrC8( (TUint8*)iBuffer, KBufferSize*2 ) ); 
 
	// store pointer of this class to thread local store 
	// for use in ExcHandler ( static function ) 
	Dll::SetTls( this ); 
	RThread().SetExceptionHandler( ExcHandler, 0xffffffff ); 
 
	} 
 
CMixerThread::CMixerThread( TAny* aData ) 
	: iShared( *((TAudioShared*)aData) ) 
	{ 
	} 
 
CMixerThread::~CMixerThread() 
	{ 
	delete iStream; 
	delete iBuffer; 
	delete iMixBuffer; 
 
	delete iActiveScheduler; 
	delete iCleanupStack; 
	} 
 
void CMixerThread::ExcHandler( TExcType aExc ) 
	{ 
	// exception handler entry function 
	CMixerThread* mixerPointer = (CMixerThread*)Dll::Tls(); 
	mixerPointer->HandleException( aExc ); 
	} 
 
void CMixerThread::HandleException( TExcType aExc ) 
	{ 
	// handle exceptions 
	// exception type EExcUserInterrupt is reserved for inter-thread communication 
	switch( aExc ) 
		{ 
		case EExcUserInterrupt:				// Command from client 
			{ 
			switch( iShared.iCmd ) 
				{ 
				case ECmdStartMixer: 
					{ 
					StartMixer(); 
					break; 
					} 
				case ECmdStopMixer: 
					{ 
					StopMixer(); 
					break; 
					} 
				case ECmdDestroyMixer: 
					{ 
					CActiveScheduler::Stop();		// Exit 
					break; 
					} 
 
				} 
			break; 
			} 
		default: 
			{ 
			// if unknown exception, just exit this thread 
			CActiveScheduler::Stop();				// Exit 
			break; 
			} 
		} 
 
	} 
 
 
void CMixerThread::StartMixer() 
	{ 
	iStream = CMdaAudioOutputStream::NewL( *this ); 
	iStream->Open( &iSet ); 
	} 
 
 
void CMixerThread::StopMixer() 
	{ 
	iStream->Stop(); 
	delete iStream; 
	iStream = NULL; 
	} 
 
void CMixerThread::FillBuffer() 
	{ 
	// wait for access to shared data 
	iShared.iMutex.Wait(); 
 
	TInt volume = iShared.iMainVolume; 
	// 
	// Gather new sample information 
	// 
	TInt i; 
	for( i=0; i> KAudioShift ] * volume ); 
				pos += posAdd; 
				if( pos >= posEnd ) 
					{ 
					if( repEnd == 0 ) 
						{ 
						iAudioData[ i ] = NULL; 
						break; 
						} 
					else 
						{ 
						pos = repStart; 
						posEnd = repEnd; 
						} 
					} 
				*buf++ += sample; 
				} 
			iAudioPos[ i ] = pos; 
			iAudioEnd[ i ] = posEnd; 
 
			} 
		} 
 
 
	// convert 32-bit mixing buffer to 16-bit output buffer 
	TInt* buf = iMixBuffer; 
	TInt* bufEnd = buf + KBufferSize; 
	TInt16* buf2 = iBuffer; 
	while( buf < bufEnd ) 
		{ 
		// 32-bit mixer buffer contents are multiplied by main volume 
		// shifts are in two phases to prevent overflow and maintain quality 
		TInt value = ( ( *buf++ >> 8 ) * volume ) >> 8; 
 
		// Prevent sound from trashing on overboost volume: 
		if( value < -0x7fff ) value = -0x7fff; 
		if( value > 0x7fff ) value = 0x7fff; 
 
		// and write to buffer 
		*buf2++ = (TInt16)value; 
		} 
 
	// write 16-bit buffer to CMdaAudioOutputStream 
	iStream->WriteL( iBufferPtr ); 
	} 
 
void CMixerThread::MaoscBufferCopied( TInt aError, const TDesC8& /*aBuffer*/ ) 
	{ 
	if( aError ) 
		{ 
		iError = aError; 
		} 
	else 
		{ 
		FillBuffer(); 
		} 
	} 
 
void CMixerThread::MaoscOpenComplete( TInt aError ) 
	{ 
	if( aError ) 
		{ 
		iError = aError; 
		} 
	else 
		{ 
		iStream->SetVolume( iStream->MaxVolume() ); 
		FillBuffer(); 
		} 
	} 
 
void CMixerThread::MaoscPlayComplete( TInt aError ) 
	{ 
	if( aError ) 
		{ 
		iError = aError; 
		} 
	else 
		{ 
		iStream->SetVolume( iStream->MaxVolume() ); 
		FillBuffer(); 
		} 
	}