CMixerThread.cpp
上传用户:snevogroup
上传日期:2008-06-06
资源大小:432k
文件大小:6k
源码类别:

Symbian

开发平台:

C/C++

  1. // INCLUDES
  2. #include "CMixerThread.h"
  3. #include <e32svr.h>
  4. #include "TSample.h"
  5. #include "TAudioShared.h"
  6. // CONSTANTS
  7. const TInt KSampleRate = 16000;                 // sample rate used
  8. const TInt KBufferSize = KSampleRate / 20; // 20 buffers per second
  9. TInt CMixerThread::ThreadFunction( TAny* aData )
  10. {
  11. TAudioShared& shared = *((TAudioShared*)aData);
  12. // tell client we're alive
  13. // signaled off when destroying this thread
  14. shared.iAliveMutex.Wait();
  15. CMixerThread* mixerThread = CMixerThread::Create( aData );
  16. if( mixerThread == NULL )
  17. {
  18. return KErrGeneral;
  19. }
  20. // if we're still here, activescheduler has been constructed
  21. // start wait loop which runs until it's time to end the thread
  22. CActiveScheduler::Start();
  23. delete mixerThread;
  24. // tell owning thread it's safe to exit
  25. shared.iAliveMutex.Signal();
  26.     return KErrNone;
  27. }
  28. CMixerThread* CMixerThread::Create( TAny* aData )
  29. {
  30. CMixerThread* self = new CMixerThread( aData );
  31. if( self == NULL ) 
  32. return self;
  33. if( self->Construct() != KErrNone )
  34. {
  35. delete self;
  36. return NULL;
  37. }
  38. return self;
  39. }
  40. TInt CMixerThread::Construct()
  41. {
  42. // create cleanup stack
  43. iCleanupStack = CTrapCleanup::New();
  44. if( iCleanupStack == NULL )
  45. {
  46. return KErrNoMemory;
  47. }
  48. TInt err = KErrNone;
  49. TRAP( err, ConstructL() );
  50. return err;
  51. }
  52. void CMixerThread::ConstructL()
  53. {
  54. // create active scheduler
  55. iActiveScheduler = new( ELeave )CActiveScheduler;
  56. CActiveScheduler::Install( iActiveScheduler );
  57. // sound inits
  58. iSet.iChannels = TMdaAudioDataSettings::EChannelsMono;
  59. iSet.iSampleRate = TMdaAudioDataSettings::ESampleRate16000Hz;
  60. iSet.iVolume = 1;
  61. iMixBuffer = new( ELeave )TInt[ KBufferSize ];
  62. iBuffer = new( ELeave )TInt16[ KBufferSize ];
  63. iBufferPtr.Set( TPtrC8( (TUint8*)iBuffer, KBufferSize*2 ) );
  64. // store pointer of this class to thread local store
  65. // for use in ExcHandler ( static function )
  66. Dll::SetTls( this );
  67. RThread().SetExceptionHandler( ExcHandler, 0xffffffff );
  68. }
  69. CMixerThread::CMixerThread( TAny* aData )
  70. : iShared( *((TAudioShared*)aData) )
  71. {}
  72. CMixerThread::~CMixerThread()
  73. {
  74. delete iStream;
  75. delete iBuffer;
  76. delete iMixBuffer;
  77. delete iActiveScheduler;
  78. delete iCleanupStack;
  79. }
  80. void CMixerThread::ExcHandler( TExcType aExc )
  81. {
  82. // exception handler entry function
  83. CMixerThread* mixerPointer = (CMixerThread*)Dll::Tls();
  84. mixerPointer->HandleException( aExc );
  85. }
  86. void CMixerThread::HandleException( TExcType aExc )
  87. {
  88. // handle exceptions
  89. // exception type EExcUserInterrupt is reserved for inter-thread communication
  90. switch( aExc )
  91. {
  92. case EExcUserInterrupt: // Command from client
  93. {
  94. switch( iShared.iCmd )
  95. {
  96. case ECmdStartMixer:
  97. {
  98. StartMixer();
  99. }break;
  100. case ECmdStopMixer:
  101. {
  102. StopMixer();
  103. }break;
  104. case ECmdDestroyMixer:
  105. {
  106. CActiveScheduler::Stop(); // Exit
  107. }break;
  108. }
  109. }break;
  110. default:
  111. {
  112. // if unknown exception, just exit this thread
  113. CActiveScheduler::Stop(); // Exit
  114. }break;
  115. }
  116. }
  117. void CMixerThread::StartMixer()
  118. {
  119. iStream = CMdaAudioOutputStream::NewL( *this );
  120. iStream->Open( &iSet );
  121. }
  122. void CMixerThread::StopMixer()
  123. {
  124. iStream->Stop();
  125. delete iStream;
  126. iStream = NULL;
  127. }
  128. void CMixerThread::FillBuffer()
  129. {
  130. // wait for access to shared data
  131. iShared.iMutex.Wait();
  132. TInt volume = iShared.iMainVolume;
  133. //
  134. // Gather new sample information
  135. //
  136. TInt i;
  137. for( i=0; i<KMaxChannels; i++ )
  138. {
  139. if( iShared.iPlayStarted[ i ] )
  140. {
  141. iShared.iPlayStarted[ i ] = EFalse;
  142. TSample& s = iShared.iSample[ i ];
  143. iAudioData[ i ] = s.iData;
  144. iAudioPos[ i ] = 0;
  145. iAudioEnd[ i ] = s.iLength << KAudioShift;
  146. iRepStart[ i ] = s.iRepStart << KAudioShift;
  147. iRepEnd[ i ] = s.iRepEnd << KAudioShift;
  148. }
  149. }
  150. // give access to shared data
  151. iShared.iMutex.Signal();
  152. //
  153. // Clear buffer
  154. // has to be done because channels are mixed by adding their values
  155. // to each other
  156. //
  157. Mem::FillZ( iMixBuffer, KBufferSize*4 );
  158. //
  159. // Mix active channels
  160. //
  161. for( i=0; i<KMaxChannels; i++ )
  162. {
  163. if( iAudioData[ i ] != NULL )
  164. {
  165. TInt* buf = iMixBuffer;
  166. TInt* bufEnd = buf + KBufferSize;
  167. TInt16* src = iAudioData[ i ];
  168. TInt pos = iAudioPos[ i ];
  169. TInt posEnd = iAudioEnd[ i ];
  170. TInt repStart = iRepStart[ i ];
  171. TInt repEnd = iRepEnd[ i ];
  172. TInt posAdd = ( iShared.iFrequency[ i ] << KAudioShift ) / KSampleRate;
  173. TInt volume = iShared.iVolume[ i ];
  174. while( buf < bufEnd )
  175. {
  176. TInt sample = ( src[ pos >> KAudioShift ] * volume );
  177. pos += posAdd;
  178. if( pos >= posEnd )
  179. {
  180. if( repEnd == 0 )
  181. {
  182. iAudioData[ i ] = NULL;
  183. break;
  184. }
  185. else
  186. {
  187. pos = repStart;
  188. posEnd = repEnd;
  189. }
  190. }
  191. *buf++ += sample;
  192. }
  193. iAudioPos[ i ] = pos;
  194. iAudioEnd[ i ] = posEnd;
  195. }
  196. }
  197. // convert 32-bit mixing buffer to 16-bit output buffer
  198. TInt* buf = iMixBuffer;
  199. TInt* bufEnd = buf + KBufferSize;
  200. TInt16* buf2 = iBuffer;
  201. while( buf < bufEnd )
  202. {
  203. // 32-bit mixer buffer contents are multiplied by main volume
  204. // shifts are in two phases to prevent overflow and maintain quality
  205. TInt value = ( ( *buf++ >> 8 ) * volume ) >> 8;
  206. // Prevent sound from trashing on overboost volume:
  207. if( value < -0x7fff ) value = -0x7fff;
  208. if( value > 0x7fff ) value = 0x7fff;
  209. // and write to buffer
  210. *buf2++ = (TInt16)value;
  211. }
  212. // write 16-bit buffer to CMdaAudioOutputStream
  213. iStream->WriteL( iBufferPtr );
  214. }
  215. void CMixerThread::MaoscBufferCopied( TInt aError, const TDesC8& /*aBuffer*/ )
  216. {
  217. if( aError )
  218. {
  219. iError = aError;
  220. }
  221. else
  222. {
  223. FillBuffer();
  224. }
  225. }
  226. void CMixerThread::MaoscOpenComplete( TInt aError )
  227. {
  228. if( aError )
  229. {
  230. iError = aError;
  231. }
  232. else
  233. {
  234. iStream->SetVolume( iStream->MaxVolume() );
  235. FillBuffer();
  236. }
  237. }
  238. void CMixerThread::MaoscPlayComplete( TInt aError )
  239. {
  240. if( aError )
  241. {
  242. iError = aError;
  243. }
  244. else
  245. {
  246. iStream->SetVolume( iStream->MaxVolume() );
  247. FillBuffer();
  248. }
  249. }