emulator/emulatorbsp/specific/soundsc_rx.cpp
changeset 0 cec860690d41
equal deleted inserted replaced
-1:000000000000 0:cec860690d41
       
     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