os/boardsupport/emulator/emulatorbsp/specific/soundsc_rx.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // wins\specific\soundsc_rx.cpp
    15 // Emulator record functions for the shared chunk sound driver PDD.
    16 // 
    17 //
    18 
    19 /**
    20  @file
    21  @internalTechnology
    22  @prototype
    23 */
    24 
    25 #include "winssoundsc.h"
    26 
    27 /**
    28 The thread function for the record windows thread.
    29 This function is always executed in windows thread context.
    30 */
    31 LOCAL_C TUint RecordThreadFunction(DWinsSoundScRxPdd *aSoundPdd)
    32 	{
    33 	aSoundPdd->RecordThread();
    34 	return 0;
    35 	}
    36 		
    37 /**
    38 The waveform input callback function. This can receive the following messages:-
    39 WIM_OPEN when the input device is opened, WIM_CLOSE when the input device is closed,
    40 and WIM_DATA each time a record data block has been filled (i.e. completion of waveInAddBuffer).
    41 This function is always executed in windows thread context.
    42 */
    43 LOCAL_C void CALLBACK WaveInProc(HWAVEIN /*hwi*/, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD /*dwParam2*/)
    44 	{
    45 	if (uMsg == WIM_DATA)
    46 		{
    47 		DWinsSoundScRxPdd * pdd = (DWinsSoundScRxPdd*)dwInstance;
    48 		pdd->WaveInProc((WAVEHDR*)dwParam1);
    49 		}
    50 	}			
    51 
    52 /**
    53 Constructor for the WINS shared chunk record PDD.
    54 This function is always executed in driver thread context.
    55 */
    56 DWinsSoundScRxPdd::DWinsSoundScRxPdd()
    57 	: iDfc(DWinsSoundScRxPdd::RecordDfc,this,2)
    58 	{		
    59 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::DWinsSoundScRxPdd"));
    60 	
    61 //	iDriverThreadSem=0;
    62 //	iRecordThread=0;
    63 //	iRecordThreadMutex=0;
    64 //	iRecordThreadSem=0;
    65 //	iStopSemaphore=0;
    66 //	iDeathSemaphore=0;
    67 //	iRecordDeviceHandle=0;
    68 //	iRecordCommand=ERecData;
    69 //	iRecordCommandArg0=0;
    70 //	iRecordCommandArg1=0;
    71 //	iPendingRecord=0;
    72 //	iRecordThreadError=0;
    73 ///	iWaveformBufMgr=NULL;
    74 //	iCompletedRecordBufHdrMask=0;
    75 //	iRecordBufferSize=0;
    76 //	iRecordEnabled=EFalse;
    77 //	iNoHardware=EFalse;
    78 //	iRecordTimerEvent=0;
    79 //	iTimerID=0;
    80 //	iTimerActive=EFalse;
    81 	}
    82 	
    83 /**
    84 Destructor for the WINS shared chunk record PDD.
    85 This function is always executed in driver thread context.
    86 */
    87 DWinsSoundScRxPdd::~DWinsSoundScRxPdd()
    88 	{
    89 	// If the Windows thread started up successfully, signal it to shut down and wait for it to do so
    90 	if (iRecordThreadRunning)
    91 		{
    92 		// Signal the windows thread to close down the record device and exit the windows thread.
    93 		iDeathSemaphore = CreateSemaphore(NULL, 0, 2, NULL);
    94 		RecordThreadCommand(EExit);
    95 	
    96 		// Wait for the record thread to terminate.
    97 		if (iDeathSemaphore)
    98 			{
    99 			Emulator::Escape();
   100 			WaitForSingleObject(iDeathSemaphore, INFINITE); 
   101 			Emulator::Reenter();
   102 
   103 			__HOST_LOCK;
   104 			CloseHandle(iDeathSemaphore);
   105 			}
   106 		}
   107 		
   108 	if (iRecordTimerEvent)
   109 		CloseHandle(iRecordTimerEvent); 
   110 	if (iRecordThreadSem)
   111 		CloseHandle(iRecordThreadSem); 
   112 	if (iRecordThread)
   113 		CloseHandle(iRecordThread);
   114 	if (iDriverThreadSem)
   115 		CloseHandle(iDriverThreadSem); 	
   116 	
   117 	if (iWaveformBufMgr)
   118 		delete iWaveformBufMgr;
   119 	}
   120 	
   121 /**
   122 Second stage constructor for the WINS shared chunk record PDD.
   123 Note that this constructor is called before the second stage constructor for the LDD so it is not
   124 possible to call methods on the LDD here.
   125 This function is always executed in driver thread context.
   126 @param aPhysicalDevice A pointer to the factory class that is creating this PDD.
   127 @return KErrNone if successful, otherwise one of the other system wide error codes.
   128 */	
   129 TInt DWinsSoundScRxPdd::DoCreate(DWinsSoundScPddFactory* aPhysicalDevice)
   130 	{
   131 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::DoCreate"));
   132 
   133 	iPhysicalDevice=aPhysicalDevice;
   134 	
   135 	// Set up the correct DFC queue.
   136 	iDfc.SetDfcQ(iPhysicalDevice->iDfcQ);
   137 	
   138 	SetCaps();	// Setup the capabilities of this device.
   139 	
   140 	// Setup the default audio configuration
   141 	iSoundConfig.iChannels=2;
   142 	iSoundConfig.iRate=ESoundRate48000Hz;
   143 	iSoundConfig.iEncoding=ESoundEncoding16BitPCM;
   144 	iSoundConfig.iDataFormat=ESoundDataFormatInterleaved;
   145 	
   146 	__HOST_LOCK;
   147 
   148 	// Query the waveform device capabilities using the default device identifier in order
   149 	// to check if there is a functioning waveform device present.  Note that some versions of
   150 	// Windows (such as Windows Server 2003) will actually return MMSYSERR_NOERROR when this is
   151 	// called, even if there is no waveform device present, so we have a further check in
   152 	// when waveInOpen() is called
   153 	WAVEINCAPS waveInCaps;
   154 	MMRESULT res = waveInGetDevCaps(WAVE_MAPPER,&waveInCaps,sizeof(WAVEINCAPS));
   155 #ifdef FORCE_NO_HARDWARE
   156 	res=MMSYSERR_NOERROR+1;
   157 #endif
   158 	if (res != MMSYSERR_NOERROR)
   159 		iNoHardware = ETrue;
   160 	
   161 	__HOST_LOCK_OFF;
   162 	
   163 	// Create the windows waveform audio buffer manager.
   164 	iWaveformBufMgr=new TWaveformBufMgr(ESoundDirRecord,!iNoHardware);
   165 	if (!iWaveformBufMgr)
   166 		return(KErrNoMemory);
   167 	
   168 	// Create the driver thread semaphore.
   169 	iDriverThreadSem = CreateSemaphore(NULL,0,0x7fffffff,NULL);
   170 	if (!iDriverThreadSem)
   171 		return(KErrNoMemory);
   172 	
   173 	// Create the record windows thread.
   174 	if ((iRecordThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)RecordThreadFunction,(void *)this, FALSE))==NULL)
   175 		return(Emulator::LastError());
   176 	SetThreadPriority(iRecordThread,THREAD_PRIORITY_HIGHEST);
   177 	__ASSERT_ALWAYS( ResumeThread(iRecordThread) != 0xffffffff, PANIC()); //Windows Unexpected Error
   178 	
   179 	// Wait to be notified of successful thread initialization
   180 	Emulator::Escape();
   181 	WaitForSingleObject(iDriverThreadSem,INFINITE);
   182 	Emulator::Reenter();
   183 
   184 	// If the Windows thread started up successfully, indicate this fact so that when shutting down we know
   185 	// to signal to the thread to exit
   186 	if (iRecordThreadError == KErrNone)
   187 		iRecordThreadRunning = ETrue;
   188 
   189 	return(iRecordThreadError);
   190 	}
   191 
   192 /**
   193 Called from the LDD to return the DFC queue to be used by this device.
   194 This function is always executed in driver thread context.
   195 @return The DFC queue to use.
   196 */	
   197 TDfcQue* DWinsSoundScRxPdd::DfcQ(TInt /*aUnit*/)
   198 	{
   199 	return(iPhysicalDevice->iDfcQ);
   200 	}
   201 
   202 /** 
   203 Called from the LDD to return the shared chunk create information to be used by this device.
   204 This function is always executed in driver thread context.
   205 @param aChunkCreateInfo A chunk create info. object to be to be filled with the settings
   206 						required for this device.
   207 */		
   208 void DWinsSoundScRxPdd::GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo)
   209 	{
   210 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::GetChunkCreateInfo"));
   211 
   212 	aChunkCreateInfo.iType=TChunkCreateInfo::ESharedKernelMultiple;
   213 	aChunkCreateInfo.iMapAttr=0;
   214 	aChunkCreateInfo.iOwnsMemory=ETrue; 				// Using RAM pages.
   215 	aChunkCreateInfo.iDestroyedDfc=NULL; 				// No chunk destroy DFC.
   216 	}
   217 	
   218 /**
   219 Called from the LDD to return the capabilities of this device.
   220 This function is always executed in driver thread context.
   221 @param aCapsBuf A packaged TSoundFormatsSupportedV02 object to be filled with the record
   222 				capabilities of this device. This descriptor is in kernel memory and can be accessed directly.
   223 @see TSoundFormatsSupportedV02.
   224 */
   225 void DWinsSoundScRxPdd::Caps(TDes8& aCapsBuf) const
   226 	{
   227 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::Caps"));
   228 	
   229 	// Copy iCaps back.
   230 	TPtrC8 ptr((const TUint8*)&iCaps,sizeof(iCaps));
   231 	aCapsBuf.FillZ(aCapsBuf.MaxLength());
   232 	aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength()));	
   233 	}
   234 	
   235 /**
   236 Called from the LDD to return the maximum transfer length in bytes that this device can support in a single data transfer.
   237 @return The maximum transfer length in bytes.
   238 */
   239 TInt DWinsSoundScRxPdd::MaxTransferLen() const
   240 	{
   241 	return(KWinsMaxAudioTransferLen);		// 32K
   242 	}		
   243 				
   244 /**
   245 Called from the LDD to power up the sound device.
   246 This function is always executed in driver thread context.
   247 @return KErrNone if successful, otherwise one of the other system wide error codes.
   248 */
   249 TInt DWinsSoundScRxPdd::PowerUp()
   250 	{
   251 	return(KErrNone);
   252 	}
   253 
   254 /**
   255 Called from the LDD to configure or reconfigure the device using the the configuration supplied.
   256 This function is always executed in driver thread context.
   257 @param aConfigBuf A packaged TCurrentSoundFormatV02 object which contains the new configuration settings.
   258 				  This descriptor is in kernel memory and can be accessed directly.
   259 @return KErrNone if successful, otherwise one of the other system wide error codes.
   260 @see TCurrentSoundFormatV02.
   261 */	
   262 TInt DWinsSoundScRxPdd::SetConfig(const TDesC8& aConfigBuf)
   263 	{
   264 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::SetConfig"));
   265 
   266 	// Cannot change the configuration while the device is open and recording. (LDD should prevent
   267 	// this anyway but better safe than sorry).
   268 	if (iRecordDeviceHandle)
   269 		return(KErrInUse);
   270 	
   271 	// Save the current settings so we can restore them if there is a problem with the new ones.
   272 	TCurrentSoundFormatV02 saved=iSoundConfig;
   273 	
   274 	// Read the new configuration from the LDD.
   275 	TPtr8 ptr((TUint8*)&iSoundConfig,sizeof(iSoundConfig));
   276 	Kern::InfoCopy(ptr,aConfigBuf);
   277 	
   278 	// Open the record device with the new settings to check they are supported. Then close it
   279 	// again - don't leave it open yet.
   280 	TInt r = CreateRecordDevice(ETrue);
   281 	if (r==KErrNone)
   282 		CloseRecordDevice();
   283 	else
   284 		iSoundConfig=saved;	// Restore the previous settings
   285 	
   286 	return(r);
   287 	}
   288 
   289 /**
   290 Called from the LDD to set the record level.
   291 This function is always executed in driver thread context.
   292 @param aLevel The record level to be set - a value in the range 0 to 255. The value 255 equates 
   293 	   to the maximum record level and each value below this equates to a 0.5dB step below it.
   294 @return KErrNone if successful, otherwise one of the other system wide error codes.
   295 */
   296 TInt DWinsSoundScRxPdd::SetVolume(TInt /*aVolume*/)
   297 	{
   298 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::SetVolume"));
   299 	
   300 	// There's no adjustment of the record level on the wave in device.
   301 	
   302 	return(KErrNone);
   303 	}
   304 	
   305 /**
   306 Called from the LDD to prepare the audio device for recording.
   307 This function is always executed in driver thread context.
   308 @return KErrNone if successful, otherwise one of the other system wide error codes.
   309 */
   310 TInt DWinsSoundScRxPdd::StartTransfer()
   311 	{
   312 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::StartTransfer"));
   313 
   314 	// Convert the enum representing the current sample rate into an integer
   315 	TInt samplesPerSecond=RateInSamplesPerSecond(iSoundConfig.iRate);
   316 	if (samplesPerSecond==0)
   317 		return(KErrNotSupported);
   318 
   319 	// Now convert the sample rate into the number of bytes per second and save for later use
   320 	iBytesPerSecond=samplesPerSecond;
   321 	if (iSoundConfig.iChannels==2)
   322 		iBytesPerSecond*=2;
   323 	if (iSoundConfig.iEncoding==ESoundEncoding16BitPCM)
   324 		iBytesPerSecond*=2;
   325 
   326 	iBytesRecordedBeforeLastPause = 0;
   327 	iBytesSincePauseReportedToLdd = 0;
   328 
   329 	iRecordEnabled=ETrue;
   330 
   331 	// Open the record device with the current settings.
   332 	iPendingRecord=0;
   333 	iCompletedRecordBufHdrMask=0;					// Reset the completion status mask
   334 	TInt r = CreateRecordDevice();
   335 	return(r);
   336 	}
   337 	
   338 /**
   339 Called from the LDD to initiate the recording of a portion of data from the audio device. 
   340 When the transfer is complete, the PDD signals this event using the LDD function RecordCallback().
   341 This function is always executed in driver thread context.
   342 @param aTransferID A value assigned by the LDD to allow it to uniquely identify a particular transfer fragment.
   343 @param aLinAddr The linear address within the shared chunk for storing the recorded data.
   344 @param aPhysAddr The physical address within the shared chunk for storing the recorded data.
   345 @param aNumBytes The number of bytes to be recorded. 
   346 @return KErrNone if the transfer has been initiated successfully;
   347   		KErrNotReady if the device is unable to accept the transfer for the moment;
   348 		otherwise one of the other system-wide error codes.
   349 */
   350 TInt DWinsSoundScRxPdd::TransferData(TUint aTransferID,TLinAddr aLinAddr,TPhysAddr /*aPhysAddr*/,TInt aNumBytes)
   351 	{
   352 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::TransferData(ID:%xH)",aTransferID));
   353 	
   354 	// Check that we can accept the request
   355 	if (aNumBytes>KWinsMaxAudioTransferLen)
   356 		return(KErrArgument);
   357 	if (iPendingRecord>=iWaveformBufMgr->iNumWaveformBufs)	// LDD may issue multiple data transfers per buffer.
   358 		return(KErrNotReady);
   359 	
   360 	// Signal the windows thread to initiate the recording of a buffers worth of data from the wavein device.
   361 	iPendingRecord++;
   362 	RecordThreadCommand(ERecData,aTransferID,aLinAddr,aNumBytes);
   363 	
   364 	// Although the windows thread runs at a higher priority, its not safe to assume we will always get pre-empted at this
   365 	// point while the the higher priority thread processes and completes the request. Instead we need to wait until it
   366 	// signals back completion of the command.
   367 	Emulator::Escape();
   368 	WaitForSingleObject(iDriverThreadSem,INFINITE);
   369 	Emulator::Reenter();	
   370 
   371 	return(iRecordThreadError);	
   372 	}
   373 
   374 /**
   375 Called from the LDD to terminate the recording of a data from the device and to release any resources necessary for
   376 recording.
   377 The LDD will leave the audio device capturing record data even when there are no record requests pending from the client.
   378 Transfer will only be terminated when the client either issues RSoundSc::CancelRecordData() or closes the channel. Once
   379 this function had been called, the LDD will not issue  any further TransferData() commands without first issueing a
   380 StartTransfer() command.
   381 This function is always executed in driver thread context.
   382 */
   383 void DWinsSoundScRxPdd::StopTransfer()
   384 	{
   385 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::StopTransfer"));
   386 	
   387 	// Signal the windows thread to stop it from sending any more buffers to wavein device.
   388 	iStopSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
   389 	RecordThreadCommand(EStop);
   390 
   391 	// Need to wait for the record thread to finish using the record handle before it's safe to close the device and 
   392 	// set the handle to NULL.
   393 	if (iStopSemaphore)
   394 		{
   395 		// Wait for the record thread to stop.
   396 		Emulator::Escape();
   397 		WaitForSingleObject(iStopSemaphore, INFINITE);  
   398 		Emulator::Reenter();
   399 
   400 		__HOST_LOCK;
   401 		CloseHandle(iStopSemaphore);
   402 		iStopSemaphore = NULL;
   403 		}
   404 		
   405 	// Make sure the DFC is not queued.
   406 	iDfc.Cancel();	
   407 			
   408 	CloseRecordDevice();							// Close down the record device.
   409 	iPendingRecord=0;
   410 	iCompletedRecordBufHdrMask=0;					// Reset the completion status mask
   411 	}
   412 
   413 /**
   414 Called from the LDD to halt the recording of data from the sound device but not to release any resources necessary for
   415 recording.
   416 All active transfers should be aborted. When recording is halted the PDD signals this event with a single call of the LDD 
   417 function RecordCallback() - reporting back any partial data already received. If transfer is resumed later, the LDD will
   418 issue a new TransferData() request to re-commence data transfer.
   419 This function is always executed in driver thread context.
   420 @return KErrNone if successful, otherwise one of the other system wide error codes.
   421 */
   422 TInt DWinsSoundScRxPdd::PauseTransfer()
   423 	{
   424 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::PauseTransfer"));
   425 	
   426 	// Signal the windows thread to stop recording on the wavein device - aborting any transfers queued.
   427 	RecordThreadCommand(EPause);
   428 	
   429 	// Wait for the windows thread to complete the request
   430 	Emulator::Escape();
   431 	WaitForSingleObject(iDriverThreadSem,INFINITE);
   432 	Emulator::Reenter();
   433 	
   434 	// Make sure the DFC is not queued.
   435 	iDfc.Cancel();
   436 	
   437 	// The windows thread returns the total bytes recorded since the last pause (as reported by windows). 
   438 	TUint totalRecordedSincePause = iRecordThreadError;
   439 	TUint lastTransferLength = totalRecordedSincePause - iBytesSincePauseReportedToLdd;
   440 	Kern::Printf("totalRecordedSincePause %d - iBytesSincePauseReportedToLdd %d = lastTransferLength %d\n",
   441 				 totalRecordedSincePause, iBytesSincePauseReportedToLdd, lastTransferLength);
   442 
   443 	iBytesRecordedBeforeLastPause += totalRecordedSincePause;
   444 	iBytesSincePauseReportedToLdd = 0;
   445 
   446 	if (iPendingRecord)
   447 		{
   448 		Ldd()->RecordCallback(0, KErrNone, lastTransferLength);	// We can use a NULL tranfer ID when pausing.
   449 	
   450 		// The LDD will abandon any other transfers queued so we can mark all buffers as not in use.
   451     	for (TInt i=0 ; i<iWaveformBufMgr->iNumWaveformBufs ; i++)
   452     		{
   453     		TWaveformAudioBuf* buf=&iWaveformBufMgr->iWaveformAudioBuf[i];
   454     		if (buf->iIsInUse)
   455     			buf->iIsInUse=EFalse;
   456     		}
   457 		iPendingRecord=0;
   458 		}
   459 
   460 	// Indicate that all request to Windows for recording have been cancelled
   461 	iCompletedRecordBufHdrMask=0;
   462 					
   463 	return(KErrNone);
   464 	}
   465 	
   466 /**
   467 Called from the LDD to resume the recording of data from the sound device following a request to halt recording.
   468 Any active transfer would have been aborted when the device was halted so its just a case of re-creating the same setup
   469 acheived following StartTransfer().
   470 This function is always executed in driver thread context.
   471 @return KErrNone if successful, otherwise one of the other system wide error codes.
   472 */
   473 TInt DWinsSoundScRxPdd::ResumeTransfer()
   474 	{
   475 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::ResumeTransfer"));
   476 	
   477 	iPendingRecord=0;
   478 	iCompletedRecordBufHdrMask=0; // All buffers would have completed during pausing (waveInReset) so clear mask.
   479 	iRecordEnabled=ETrue; // Simply set the flag to enable the windows thread to restart sending buffers to wavein device. 
   480 
   481 	// Signal the windows thread to resume recording on the wavein device.
   482 	RecordThreadCommand(EResume);
   483 
   484 	return(KErrNone);
   485 	}
   486 	
   487 /**
   488 Called from the LDD to power down the sound device.
   489 This function is always executed in driver thread context.
   490 */
   491 void DWinsSoundScRxPdd::PowerDown()
   492 	{
   493 	
   494 	}
   495 	
   496 /**
   497 Called from the LDD to handle a custom configuration request.
   498 @param aFunction A number identifying the request.
   499 @param aParam A 32-bit value passed to the driver. Its meaning depends on the request.
   500 @return KErrNone if successful, otherwise one of the other system wide error codes.
   501 */
   502 TInt DWinsSoundScRxPdd::CustomConfig(TInt /*aFunction*/,TAny* /*aParam*/)
   503 	{
   504 	return(KErrNotSupported);
   505 	}
   506 		
   507 /**
   508 Called from the LDD to find out how many microseconds of data have been recorded.  This is called
   509 in the context of the DFC thread.
   510 @param aTimeTransferred	A reference to a variable into which to place the number of microseconds of audio.
   511 @param aStatus			The current status of this channel
   512 @return KErrNone if time is valid or KErrNotSupported.
   513 */
   514 TInt DWinsSoundScRxPdd::TimeTransferred(TInt64& aTimeRecorded, TInt aState)
   515 	{
   516 	TInt r=KErrGeneral;
   517 	TInt64 ms=0;
   518 
   519 	if(iRecordDeviceHandle == 0)
   520 		{
   521 		// Recording not started yet
   522 		aTimeRecorded = 0;
   523 		return KErrNone;
   524 		}
   525 
   526 	// Kern::Printf("DWinsSoundScRxPdd::TimeTransferred - (iBytesSincePauseReportedToLdd=%d)\n", iBytesSincePauseReportedToLdd);
   527 	if (aState == DSoundScLdd::EPaused)
   528 		{
   529 		// Kern::Printf("DWinsSoundScRxPdd::TimeTransferred (paused) - iBytesRecordedBeforeLastPause %d\n", iBytesRecordedBeforeLastPause);
   530 		// Just use the paused number of bytes
   531 		ms=((iBytesRecordedBeforeLastPause/iBytesPerSecond)*1000);
   532 		TUint remainder=(iBytesRecordedBeforeLastPause%iBytesPerSecond);
   533 		ms+=((remainder*1000)/iBytesPerSecond);
   534 		ms*=1000;
   535 		aTimeRecorded=ms;
   536 		r=KErrNone;
   537 		}
   538 
   539 	TInt64 bytesTransferredSincePause = 0;
   540 	// If no hardware is present then we need to use iBytesSincePauseReportedToLdd + a fudge factor to allow
   541 	// the number of bytes processed by the "hardware" within the current transfer.
   542 	if(iNoHardware)
   543 		{
   544 		// Determine the # of milliseconds that have passed since the last timer triggered
   545 		DWORD currentTime = timeGetTime();
   546 		DWORD timeSinceLastEvent = (currentTime - iLastTimerEventTime);
   547 
   548 		// Clamp the resulting value to the duration of the timer, to prevent the millisecond count
   549 		// going backwards if Windows is busy and latency becomes an issue
   550 		if (timeSinceLastEvent > iSimulatedMsecDuration)
   551 			timeSinceLastEvent = iSimulatedMsecDuration;
   552 
   553 		bytesTransferredSincePause = iBytesSincePauseReportedToLdd;
   554 		WAVEHDR *buf = iWaveformBufMgr->iPendingBufList[0];
   555 		if(buf)
   556 			{
   557 			// Add on an estimate of the progress of the current transfer
   558 			bytesTransferredSincePause += ((buf->dwBufferLength * timeSinceLastEvent) / iSimulatedMsecDuration);
   559 			}
   560 		}
   561 	else
   562 		{
   563 		// Get the number of bytes recorded by the Windows audio system
   564 		MMTIME time;
   565 		time.wType=TIME_BYTES;
   566 		if ((waveInGetPosition(iRecordDeviceHandle,&time,sizeof(time)) != MMSYSERR_NOERROR) ||
   567 			(time.wType != TIME_BYTES))
   568 			{
   569 			// If requesting the number of bytes recorded is not supported, wType will be
   570 			// changed to what was actually returned, so check for this and don't continue
   571 			// if we got anything other than bytes
   572 			return KErrNotSupported;
   573 			}
   574 		bytesTransferredSincePause = time.u.cb;
   575 		}
   576 
   577 	// Kern::Printf("DWinsSoundScRxPdd::TimeTransferred - iBytesRecordedBeforeLastPause %d + bytesTransferredSincePause %d total %d (iNoHardware %d)\n", 
   578 	// 			iBytesRecordedBeforeLastPause, TUint32(bytesTransferredSincePause), TUint32(bytesTransferredSincePause + iBytesRecordedBeforeLastPause), iNoHardware);
   579 	// Convert the number of bytes recorded into microseconds and return it
   580 	ms=(((bytesTransferredSincePause + iBytesRecordedBeforeLastPause)/iBytesPerSecond)*1000);
   581 	TUint64 remainder=((bytesTransferredSincePause + iBytesRecordedBeforeLastPause)%iBytesPerSecond);
   582 	ms+=((remainder*1000)/iBytesPerSecond);
   583 	ms*=1000;
   584 	aTimeRecorded=ms;
   585 	r=KErrNone;
   586 
   587 	return(r);
   588 	}
   589 
   590 /** 
   591 Prepare the waveform audio buffer for record.
   592 @param aRecordDeviceHandle The handle to the waveform audio input device.
   593 */		
   594 void TWaveformAudioBuf::DoPrepareIn(HWAVEIN aRecordDeviceHandle)
   595 	{
   596 	MMRESULT res = waveInPrepareHeader(aRecordDeviceHandle,&iBufHdr,sizeof(WAVEHDR));
   597 	__KTRACE_SND(Kern::Printf("   waveInPrepareHeader(BufNo:%d Pos:%x Len:%d)-%d",iBufNum,iBufHdr.lpData,iBufHdr.dwBufferLength,res));
   598 	__ASSERT_ALWAYS(res==MMSYSERR_NOERROR,Kern::Fault("DWinsSoundScTxPddWIPH", res)); //WaveInPrepareHeader error.	
   599 	}
   600 	
   601 /**
   602 Cleanup the preparation performed when the waveform audio buffer was prepared for record.
   603 @param aRecordDeviceHandle The handle to the waveform audio input device.
   604 */	
   605 void TWaveformAudioBuf::DoUnprepareIn(HWAVEIN aRecordDeviceHandle)
   606 	{
   607 	MMRESULT res = waveInUnprepareHeader(aRecordDeviceHandle,&iBufHdr,sizeof(WAVEHDR));
   608 	__KTRACE_SND(Kern::Printf("   waveInUnprepareHeader(BufNo:%d)-%d",iBufNum,res));
   609 	__ASSERT_ALWAYS(res==MMSYSERR_NOERROR,Kern::Fault("DWinsSoundScTxPddWIUH",res)); //WaveInUnprepareHeader error.
   610 	}
   611 															
   612 /**
   613 The waveform input callback function to handle data block transfer completion.
   614 This function is always executed in windows thread context.
   615 @param aHdr A pointer to the header for the waveform audio buffer just transferred.
   616 */	
   617 void DWinsSoundScRxPdd::WaveInProc(WAVEHDR* aHdr)
   618 	{
   619 	TInt waveBufId=aHdr->dwUser;				// Work out which waveform audio buffer is completing.
   620     // Kern::Printf("DWinsSoundScRxPdd::WaveInProc waveBufId %d", waveBufId);
   621 
   622 	StartOfInterrupt();
   623 	iCompletedRecordBufHdrMask|=(1<<waveBufId);	// Update the completion status mask
   624 	iDfc.Add();									// Queue RecordDfc().
   625 	EndOfInterrupt();
   626 	}
   627 	
   628 /**
   629 The DFC used to handle data block record completion.
   630 This function is always executed in driver thread context.
   631 @param aPtr A pointer to the physical channel object.
   632 */	
   633 void DWinsSoundScRxPdd::RecordDfc(TAny* aPtr)
   634 	{
   635 	TInt i;
   636 	DWinsSoundScRxPdd& drv=*(DWinsSoundScRxPdd*)aPtr;
   637 	
   638 	// More than 1 transfer may have completed so loop until all completions are handled
   639 	while (drv.iCompletedRecordBufHdrMask)
   640 		{
   641 		// Find the buffer ID of the next transfer that has completed
   642 		for (i=0 ; i<32 && !(drv.iCompletedRecordBufHdrMask&(1<<i)) ; i++) {}
   643 		__ASSERT_ALWAYS(i<drv.iWaveformBufMgr->iNumWaveformBufs,PANIC());
   644 		__e32_atomic_and_ord32(&drv.iCompletedRecordBufHdrMask, ~(1u<<i)); // Clear this bit in the mask
   645 		
   646 		// Update the status of the waveform audio buffer which is completing
   647 		TWaveformAudioBuf& buf=drv.iWaveformBufMgr->iWaveformAudioBuf[i];
   648 		buf.iIsInUse=EFalse;
   649 	
   650 		// Callback the LDD passing the information for the transfer that has completed
   651 		drv.iPendingRecord--;
   652 		__KTRACE_SND(Kern::Printf("   Read complete(BufNo:%x Pos:%x Len:%d)",i,buf.iBufHdr.lpData,buf.iBufHdr.dwBufferLength));
   653 		drv.iBytesSincePauseReportedToLdd += buf.iBufHdr.dwBufferLength;
   654 		drv.Ldd()->RecordCallback(buf.iTransferID,KErrNone,buf.iBufHdr.dwBufferLength);
   655 		}
   656 	}	
   657 
   658 /**
   659 Issue a request from the driver thread to the windows thread to execute a command.
   660 @param aCommand The identifier of the command to be executed.
   661 @param aArg0 A first command argument, its meaning depends on the command.
   662 @param aArg1 A second command argument, its meaning depends on the command.
   663 @param aArg2 A third command argument, its meaning depends on the command.
   664 This function is always executed in driver thread context.
   665 */
   666 void DWinsSoundScRxPdd::RecordThreadCommand(TThreadCommand aCommand,TInt aArg0,TInt aArg1,TInt aArg2)
   667 	{
   668 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd:RecordThreadCommand"));
   669 	iRecordCommand = aCommand;
   670 	iRecordCommandArg0 = aArg0;
   671 	iRecordCommandArg1 = aArg1;
   672 	iRecordCommandArg2 = aArg2;
   673 
   674 	__HOST_LOCK;
   675 
   676 	ReleaseSemaphore(iRecordThreadSem,1,NULL);
   677 	}
   678 
   679 /**
   680 Pass a value from the windows thread to the driver thread.
   681 This function is always executed in windows thread context.
   682 @param aError The value to the passed to the driver thread.
   683 */
   684 void DWinsSoundScRxPdd::RecordThreadNotifyDriver(TInt aError)
   685 	{
   686 	iRecordThreadError = aError;
   687 	BOOL ret = ReleaseSemaphore(iDriverThreadSem,1,NULL);
   688 	__ASSERT_ALWAYS(ret == TRUE,PANIC()); //Unexpected Windows Error
   689 	}
   690 
   691 #pragma warning(disable : 4702) // unreachable code
   692 /**
   693 Open the waveform input device for record. Use a default device identifier in order to select a device
   694 capable of meeting the current audio configuration. 
   695 This function can be executed in either driver thread or windows thread context.
   696 @pre The data member DWinsSoundScRxPdd::iSoundConfig must be setup with the current audio configuration.
   697 */
   698 TInt DWinsSoundScRxPdd::OpenWaveInDevice()
   699 	{
   700 	WAVEFORMATEX format;
   701 	format.wFormatTag = WAVE_FORMAT_PCM;
   702 	TUint16 bitsPerSample = 8;
   703 
   704 	switch (iSoundConfig.iEncoding)
   705 		{
   706 		case ESoundEncoding8BitPCM:
   707 			break;
   708 		case ESoundEncoding16BitPCM:
   709 			bitsPerSample = 16;
   710 			break;
   711 		default:
   712 			return KErrNotSupported;
   713 		};
   714 
   715 	TInt rateInSamplesPerSecond=RateInSamplesPerSecond(iSoundConfig.iRate);
   716 	format.nChannels = TUint16(iSoundConfig.iChannels);
   717 	format.nSamplesPerSec = rateInSamplesPerSecond;
   718 	format.nAvgBytesPerSec = rateInSamplesPerSecond * iSoundConfig.iChannels * bitsPerSample / 8;
   719 	format.nBlockAlign = TUint16(iSoundConfig.iChannels * bitsPerSample / 8);
   720 	format.wBitsPerSample = bitsPerSample;
   721 	format.cbSize = 0;
   722 
   723 	MMRESULT res = MMSYSERR_NOERROR;
   724 
   725 	__COND_HOST_LOCK;		
   726 	if (iNoHardware)
   727 		{
   728 		timeBeginPeriod(KMMTimerRes);
   729 		iRecordDeviceHandle = (HWAVEIN)1;	
   730 		}
   731 	else
   732 		{
   733 		res = waveInOpen(&iRecordDeviceHandle, WAVE_MAPPER, &format, (DWORD)::WaveInProc, (DWORD)this, CALLBACK_FUNCTION);
   734 
   735 		// On some builds of Windows (such as Windows Server 2003), the waveInGetDevCaps() trick in
   736 		// DoCreate() won't work, so we have another special check for missing hardware here
   737 		if ((res == MMSYSERR_NODRIVER) || (res == MMSYSERR_BADDEVICEID))
   738 			{
   739 			// Pretend there was no error and switch into hardware emulation mode
   740 			res = MMSYSERR_NOERROR;
   741 			iNoHardware = ETrue;
   742 			iRecordDeviceHandle = (HWAVEIN)1;	
   743 			iWaveformBufMgr->iIsHardware = EFalse;
   744 			timeBeginPeriod(KMMTimerRes);
   745 			}
   746 		}
   747 
   748 	switch (res)
   749 		{
   750 		case MMSYSERR_NOERROR: // No error
   751 			return(KErrNone);
   752 		case MMSYSERR_ALLOCATED: // Specified resource is already allocated.
   753 			return(KErrInUse);
   754 		case WAVERR_BADFORMAT: // Attempted to open with an unsupported waveform-audio format
   755 			return(KErrNotSupported);
   756 		case MMSYSERR_NOMEM: // Unable to allocate or lock memory.
   757 			return(KErrNoMemory);
   758 		default:
   759 			return(KErrUnknown);
   760 		}
   761 	}
   762 #pragma warning(default : 4702) // unreachable code
   763 
   764 /**
   765 Open the audio input device.
   766 This function is always executed in driver thread context.
   767 @pre The data members DWinsSoundScRxPdd::iSoundConfig must be setup with the current audio configuration.
   768 */
   769 TInt DWinsSoundScRxPdd::CreateRecordDevice(TBool aCheckDevice)
   770 	{
   771 	// Check if the waveform input device is already open.
   772 	if (iRecordDeviceHandle)
   773 		return(KErrNone);
   774 
   775 	__HOST_LOCK;
   776 
   777 	// Open the waveform input device for recording.
   778 	TInt err = OpenWaveInDevice();
   779 	if (err != KErrNone)
   780 		return(err);
   781 	
   782 	__HOST_LOCK_OFF;	
   783 
   784 	if (!aCheckDevice)
   785 		{
   786 		// Now, re-allocate a set of the waveform audio blocks in advance of any recording. Also, prepare one of these
   787 		// for each buffer within the shared chunk. Need to be in critical section while re-allocating the audio blocks.
   788 		NKern::ThreadEnterCS();
   789 		err=iWaveformBufMgr->ReAllocAndUpdate(Ldd()->BufConfig(),Ldd()->ChunkBase(),(TInt)iRecordDeviceHandle);
   790 		NKern::ThreadLeaveCS(); 
   791 		}
   792 		
   793 	return(err);
   794 	}
   795 
   796 /**
   797 Close down the record device.
   798 This function is always executed in driver thread context.
   799 */
   800 void DWinsSoundScRxPdd::CloseRecordDevice()
   801 	{
   802 	__COND_HOST_LOCK;
   803 
   804 	if (iNoHardware)
   805 		timeEndPeriod(KMMTimerRes);
   806 
   807 	HWAVEIN handle = iRecordDeviceHandle;
   808 
   809 	if (handle)
   810 		{
   811 		if (!iNoHardware)
   812 			waveInReset(handle);		// Stop recording.
   813 		
   814 		// Un-prepare all the waveform audio buffers.
   815 		for (TInt i=0 ; i<iWaveformBufMgr->iNumWaveformBufs ; i++)
   816 			iWaveformBufMgr->iWaveformAudioBuf[i].Unprepare((TInt)handle);
   817 		
   818 		if (!iNoHardware)
   819 			waveInClose(handle);		// Close the wavein device.
   820 		
   821 		iRecordDeviceHandle = NULL;
   822 		}
   823 	}
   824 		
   825 /**
   826 The thread function for the record windows thread.
   827 This function is always executed in windows thread context.
   828 @pre The data members DWinsSoundScRxPdd::iSoundConfig must be setup with the current audio configuration.
   829 */
   830 void DWinsSoundScRxPdd::RecordThread()
   831 	{
   832 	iRecordThreadSem = CreateSemaphore(NULL,0,0x7fffffff,NULL);
   833 	__ASSERT_ALWAYS(iRecordThreadSem,PANIC()); //No Windows Memory
   834 	iRecordTimerEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
   835 	HANDLE objects[2];
   836 	objects[0]=iRecordThreadSem;		// Indicates command from driver thread
   837 	objects[1]=iRecordTimerEvent;
   838 
   839 	// Signal driver of successful setup
   840 	RecordThreadNotifyDriver(KErrNone);
   841 	ResetEvent(iRecordTimerEvent);
   842 	FOREVER
   843 		{
   844 		DWORD ret=WaitForMultipleObjectsEx(2,objects,FALSE,INFINITE,TRUE);
   845 
   846 		switch (ret)
   847 			{
   848 			case WAIT_OBJECT_0:	// Command received from the driver thread.
   849 				if (ProcessRecordCommand(iRecordCommand,iRecordCommandArg0,iRecordCommandArg1,iRecordCommandArg2)==KErrCompletion)
   850 					return; // ********* Exit thread **************
   851 				break;
   852 			case WAIT_OBJECT_0+1:
   853 				HandleRecordTimerEvent();
   854 				break;
   855 			}
   856 		}
   857 	}
   858 	
   859 /**
   860 Process a request from the driver thread to execute a command.
   861 This function is always executed in windows thread context.
   862 @param aCommand The identifier of the command to be executed.
   863 @param aArg0 A first command argument, its meaning depends on the command.
   864 @param aArg1 A second command argument, its meaning depends on the command.
   865 @param aArg2 A third command argument, its meaning depends on the command.
   866 @return KErrCompletion if the command to exit the windows thread has been received;
   867 		KErrNone otherwise;
   868 */	
   869 TInt DWinsSoundScRxPdd::ProcessRecordCommand(TThreadCommand aCommand,TInt aArg0,TInt aArg1,TInt aArg2)
   870 	{
   871 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd:ProcessRecordCommand(%d)",aCommand));
   872 	switch(aCommand)
   873 		{	
   874 		case ERecData:	// Initiate the recording of a buffers worth of data from the wavein device.
   875 			{
   876 			if (iRecordEnabled)
   877 				{
   878 				// Acquire a windows waveform audio buffer for the transfer.
   879 				char* startAddress=(char*)aArg1;
   880 				TInt bytesToRecord=aArg2; 
   881 				__ASSERT_ALWAYS(bytesToRecord>0,PANIC());
   882 				TWaveformAudioBuf* waveformAudioBuf=iWaveformBufMgr->AcquireBuf(startAddress,bytesToRecord,(TInt)iRecordDeviceHandle);
   883 				waveformAudioBuf->iTransferID=(TUint)aArg0;
   884 				waveformAudioBuf->iBufHdr.dwBufferLength=bytesToRecord;
   885 									
   886 				if (!iNoHardware)
   887 					{
   888 					// This machine has a wavein device present. Send the buffer to the wavein device.
   889 					waveInStart(iRecordDeviceHandle); // Start input on the wavein device - safe to call this when already started.
   890 					MMRESULT res = waveInAddBuffer(iRecordDeviceHandle,&waveformAudioBuf->iBufHdr,sizeof(WAVEHDR));
   891 					__KTRACE_SND(Kern::Printf("   waveInAddBuffer(ID:%x Pos:%x Len:%d)-%d",aArg0,startAddress,bytesToRecord,res));
   892 					__ASSERT_ALWAYS(res == MMSYSERR_NOERROR,PANIC());  //WaveInAddBuffer Error
   893 					}
   894 				else	
   895 					{
   896 					// This machine has no audio hardware present so simulate the wavein device using a timer.
   897 					AddToPendingList(&waveformAudioBuf->iBufHdr,iWaveformBufMgr->iPendingBufList); // Queue the buffer on the pending list
   898 				
   899 					// Check if the timer needs starting/re-starting
   900 					if (!iTimerActive)
   901 						{
   902 						iLastTimerEventTime = timeGetTime();
   903 						StartTimer(&waveformAudioBuf->iBufHdr);
   904 						}
   905 					} 			
   906 				}
   907 		
   908 			// Signal the driver thread that we have completed the command.
   909 			RecordThreadNotifyDriver(KErrNone);
   910 			break;
   911 			}
   912 			
   913 			
   914 		case EStop:	// Terminate the recording of data from the wavein device.
   915 			{
   916 			iRecordEnabled=EFalse;	// Stop the windows thread from sending any more buffers to wavein device. 
   917 			
   918 			if (iNoHardware)
   919 				{
   920 				// This machine has no audio hardware present so simulates the waveout device using a timer.
   921 				StopTimer(ETrue);	// Stop the timer and cancel any buffers pending
   922 				}
   923 				
   924 			// Leave the driver thread to close down the record device.
   925 				
   926 			// Signal the driver thread that we have completed the command.	
   927 			if (iStopSemaphore)
   928 				{
   929 				LONG prev;
   930 				ReleaseSemaphore(iStopSemaphore,1,&prev);
   931 				}
   932 			break;
   933 			}
   934 	
   935 		case EExit:	// Close down the record device and exit the windows thread.
   936 			{
   937 			if (!iNoHardware)
   938 				{
   939 				// This machine has a wavein device present.
   940 				if (iRecordDeviceHandle)
   941 					{
   942 					waveInReset(iRecordDeviceHandle);   // Stop recording on the wavein device.
   943 					waveInClose(iRecordDeviceHandle);	// Close the wavein device.
   944 					}
   945 				}
   946 			else
   947 				{
   948 				// This machine has no audio hardware present so simulates the waveout device using a timer.
   949 				StopTimer(ETrue);	// Stop the timer and cancel any buffers pending.
   950 				}	
   951 			// Logically the record device is now shut so clear the handle.
   952 			iRecordDeviceHandle = 0;
   953 	
   954 			// Signal the driver thread that we have completed the command.		
   955 			if (iDeathSemaphore)
   956 				{
   957 				LONG prev;
   958 				ReleaseSemaphore(iDeathSemaphore,1,&prev);
   959 				}
   960 			return(KErrCompletion); 		// ********* Exit thread **************
   961 			}
   962 			
   963 		case EPause:	// Halt the recording of data from the wavein device.
   964 			iRecordEnabled=EFalse;
   965 			
   966 			DWORD position;
   967 			if (!iNoHardware)
   968 				{
   969 				// Need to try to work out how much of the current audio buffer has been filled.
   970 				MMTIME time;
   971 				time.wType = TIME_BYTES;
   972 				HWAVEIN handle = iRecordDeviceHandle;
   973 				waveInGetPosition(handle,&time,sizeof(MMTIME));
   974 				position = time.u.cb;
   975 			
   976 				// Stop recording. (Windows will mark all pending audio buffers as done).
   977 				waveInReset(handle);
   978 				}
   979 			else
   980 				{
   981 				// This machine has no audio hardware present so simulates the waveout device using a timer.
   982 
   983 				// Determine the # of milliseconds that have passed since the last timer triggered
   984 				DWORD currentTime = timeGetTime();
   985 				DWORD timeSinceLastEvent = (currentTime - iLastTimerEventTime);
   986 				
   987 				// Clamp the resulting value to the duration of the timer, to prevent the millisecond count
   988 				// going backwards if Windows is busy and latency becomes an issue
   989 				if (timeSinceLastEvent > iSimulatedMsecDuration)
   990 					timeSinceLastEvent = iSimulatedMsecDuration;
   991 				
   992 				TUint bytesTransferredSincePause = iBytesSincePauseReportedToLdd;
   993 				WAVEHDR *buf = iWaveformBufMgr->iPendingBufList[0];
   994 				if(buf)
   995 					{
   996 					// Add on an estimate of the progress of the current transfer
   997 					bytesTransferredSincePause += ((buf->dwBufferLength * timeSinceLastEvent) / iSimulatedMsecDuration);
   998 					}
   999 				
  1000 				position = bytesTransferredSincePause;
  1001  	
  1002                 StopTimer(ETrue);   // Stop the timer and cancel any buffers pending
  1003 				}	
  1004 			
  1005 			// Signal the driver thread that we have stopped recording - returning info. on any partially filled buffer.
  1006 			RecordThreadNotifyDriver(position);
  1007 			break;
  1008 
  1009 		case EResume:
  1010 			if (iNoHardware)
  1011 				{
  1012 				// Determine how long we were paused for and add that time to the time the timer last
  1013 				// triggered.  This will allow us to continue as though we had never been paused
  1014 				iLastTimerEventTime = timeGetTime();
  1015 				}
  1016 
  1017 			break;		
  1018 		} 
  1019 	return(KErrNone);	
  1020 	}
  1021 	
  1022 /**
  1023 Handle a timer expiry event. This is only used when no audio hardware is present, with a timer expiry corresponding
  1024 to the end of a data block transfer.
  1025 This function is always executed in windows thread context.
  1026 */
  1027 void DWinsSoundScRxPdd::HandleRecordTimerEvent()
  1028 	{
  1029 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd:HandleRecordTimerEvent"));
  1030 	ResetEvent(iRecordTimerEvent);	// Reset the event 
  1031 	
  1032 	// Remove the audio buffer just filled from the pending list and save it for the driver thread.
  1033 	WAVEHDR* buf=RemoveFromPendingList(iWaveformBufMgr->iPendingBufList);
  1034 	__ASSERT_ALWAYS(buf != NULL,PANIC());	
  1035 	TInt waveBufId=buf->dwUser;					// Work out which waveform audio buffer is completing.
  1036 	
  1037 	// Check if there are more audio buffers waiting to be played
  1038 	buf=iWaveformBufMgr->iPendingBufList[0];
  1039 	if (buf)
  1040 		{
  1041 		iLastTimerEventTime = timeGetTime();
  1042 		StartTimer(buf);						// Re-start the timer
  1043 		}
  1044 	else
  1045 		iTimerActive=EFalse;	
  1046 		
  1047 	// Notify that another audio buffer has been filled.
  1048 	StartOfInterrupt();
  1049 	iCompletedRecordBufHdrMask|=(1<<waveBufId);	// Update the completion status mask
  1050 	iDfc.Add();
  1051 	EndOfInterrupt();
  1052 	return;
  1053 	}
  1054 				
  1055 /**
  1056 Initialise the data member DWinsSoundScRxPdd::iCaps with the capabilities of this audio device.
  1057 */	
  1058 void DWinsSoundScRxPdd::SetCaps()
  1059 	{
  1060 	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::SetCaps"));
  1061 	
  1062 	// The data transfer direction for this unit is record.
  1063 	iCaps.iDirection=ESoundDirRecord;
  1064 	
  1065 	// Assume this unit supports mono or stereo.
  1066 	iCaps.iChannels=KSoundMonoChannel|KSoundStereoChannel;
  1067 	
  1068 	// Assume this unit supports all sample rates.
  1069 	iCaps.iRates=(KSoundRate7350Hz|KSoundRate8000Hz|KSoundRate8820Hz|KSoundRate9600Hz|KSoundRate11025Hz|
  1070 				  KSoundRate12000Hz|KSoundRate14700Hz|KSoundRate16000Hz|KSoundRate22050Hz|KSoundRate24000Hz|
  1071 				  KSoundRate29400Hz|KSoundRate32000Hz|KSoundRate44100Hz|KSoundRate48000Hz);
  1072 	
  1073 	// Assume this unit supports 8bit and 16bit PCM encoding.
  1074 	iCaps.iEncodings=(KSoundEncoding8BitPCM|KSoundEncoding16BitPCM);
  1075 	
  1076 	// This unit only supports interleaved data format
  1077 	iCaps.iDataFormats=KSoundDataFormatInterleaved;
  1078 	
  1079 	// The minimum request size that the device can support. 
  1080 	iCaps.iRequestMinSize=0;	// No restriction
  1081 	
  1082 	// The request alignment that this device requires. 
  1083 	iCaps.iRequestAlignment=0;	// No restriction
  1084 	
  1085 	// This unit is not capable of detecting changes in hardware configuration.
  1086 	iCaps.iHwConfigNotificationSupport=EFalse;
  1087 	}
  1088 /**
  1089 Start the audio timer.
  1090 The timer is only used when no audio hardware is present on the machine. This is in order to introduce a delay which is
  1091 equivelent to that incurred when transferring audio data over a real audio device.
  1092 @param aBuffer The audio buffer which would have been transferred had a real audio device been present. This contains
  1093 	information on the number of bytes to transfer.
  1094 */	
  1095 void DWinsSoundScRxPdd::StartTimer(WAVEHDR* aBuffer)
  1096 	{
  1097 	// First, need to calculate the duration of the timer in milliseconds.
  1098 	TInt bytesToPlay=aBuffer->dwBufferLength;
  1099 	iSimulatedMsecDuration = bytesToPlay*1000;
  1100 	iSimulatedMsecDuration /= (RateInSamplesPerSecond(iSoundConfig.iRate) * iSoundConfig.iChannels);
  1101 	if (iSoundConfig.iEncoding==ESoundEncoding16BitPCM)
  1102 		iSimulatedMsecDuration /= 2;
  1103 	if (iSoundConfig.iEncoding==ESoundEncoding24BitPCM)
  1104 		iSimulatedMsecDuration /= 3;
  1105 	if (iSimulatedMsecDuration<=0)
  1106 		iSimulatedMsecDuration=1;	// Round up to 1ms or timeSetEvent() will return an error.
  1107 				
  1108 	MMRESULT res = timeSetEvent(iSimulatedMsecDuration, KMMTimerRes, (LPTIMECALLBACK)iRecordTimerEvent, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
  1109 	__ASSERT_ALWAYS(res != NULL,PANIC()); 	// timeSetEvent error.	
  1110 	iTimerID = res;							// Save the identifier for the new timer event.
  1111 	iTimerActive=ETrue;
  1112 	}
  1113 
  1114 /**
  1115 Stop the audio timer.
  1116 The timer is only used when no audio hardware is present on the machine. This is in order to introduce a delay which is
  1117 equivelent to that incurred when transferring audio data over a real audio device.
  1118 @param aCancellAll Set to ETrue in order to discard any buffers queued on the pending buffer list. EFalse otherwise.
  1119 */	
  1120 void DWinsSoundScRxPdd::StopTimer(TBool aCancelAll)
  1121 	{
  1122 	if (iTimerActive)
  1123 		{
  1124 		MMRESULT res = timeKillEvent(iTimerID);
  1125 		__ASSERT_ALWAYS(res == TIMERR_NOERROR,PANIC()); // timeKillEvent error	
  1126 		
  1127 		if (aCancelAll)
  1128 			{
  1129 			WAVEHDR* b;
  1130 			do
  1131 				b=RemoveFromPendingList(iWaveformBufMgr->iPendingBufList);
  1132 			while(b);
  1133 			}
  1134 		}
  1135 	iTimerActive=EFalse;
  1136 	}	
  1137 
  1138