📄 cmixerthread.cpp
字号:
// INCLUDES
#include "CMixerThread.h"
#include <e32svr.h>
#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<KMaxChannels; i++ )
{
if( iShared.iPlayStarted[ i ] )
{
iShared.iPlayStarted[ i ] = EFalse;
TSample& s = iShared.iSample[ i ];
iAudioData[ i ] = s.iData;
iAudioPos[ i ] = 0;
iAudioEnd[ i ] = s.iLength << KAudioShift;
iRepStart[ i ] = s.iRepStart << KAudioShift;
iRepEnd[ i ] = s.iRepEnd << KAudioShift;
}
}
// give access to shared data
iShared.iMutex.Signal();
//
// Clear buffer
// has to be done because channels are mixed by adding their values
// to each other
//
Mem::FillZ( iMixBuffer, KBufferSize*4 );
//
// Mix active channels
//
for( i=0; i<KMaxChannels; i++ )
{
if( iAudioData[ i ] != NULL )
{
TInt* buf = iMixBuffer;
TInt* bufEnd = buf + KBufferSize;
TInt16* src = iAudioData[ i ];
TInt pos = iAudioPos[ i ];
TInt posEnd = iAudioEnd[ i ];
TInt repStart = iRepStart[ i ];
TInt repEnd = iRepEnd[ i ];
TInt posAdd = ( iShared.iFrequency[ i ] << KAudioShift ) / KSampleRate;
TInt volume = iShared.iVolume[ i ];
while( buf < bufEnd )
{
TInt sample = ( src[ pos >> 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();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -