os/boardsupport/emulator/emulatorbsp/specific/soundsc_rx.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/boardsupport/emulator/emulatorbsp/specific/soundsc_rx.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1138 @@
     1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// wins\specific\soundsc_rx.cpp
    1.18 +// Emulator record functions for the shared chunk sound driver PDD.
    1.19 +// 
    1.20 +//
    1.21 +
    1.22 +/**
    1.23 + @file
    1.24 + @internalTechnology
    1.25 + @prototype
    1.26 +*/
    1.27 +
    1.28 +#include "winssoundsc.h"
    1.29 +
    1.30 +/**
    1.31 +The thread function for the record windows thread.
    1.32 +This function is always executed in windows thread context.
    1.33 +*/
    1.34 +LOCAL_C TUint RecordThreadFunction(DWinsSoundScRxPdd *aSoundPdd)
    1.35 +	{
    1.36 +	aSoundPdd->RecordThread();
    1.37 +	return 0;
    1.38 +	}
    1.39 +		
    1.40 +/**
    1.41 +The waveform input callback function. This can receive the following messages:-
    1.42 +WIM_OPEN when the input device is opened, WIM_CLOSE when the input device is closed,
    1.43 +and WIM_DATA each time a record data block has been filled (i.e. completion of waveInAddBuffer).
    1.44 +This function is always executed in windows thread context.
    1.45 +*/
    1.46 +LOCAL_C void CALLBACK WaveInProc(HWAVEIN /*hwi*/, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD /*dwParam2*/)
    1.47 +	{
    1.48 +	if (uMsg == WIM_DATA)
    1.49 +		{
    1.50 +		DWinsSoundScRxPdd * pdd = (DWinsSoundScRxPdd*)dwInstance;
    1.51 +		pdd->WaveInProc((WAVEHDR*)dwParam1);
    1.52 +		}
    1.53 +	}			
    1.54 +
    1.55 +/**
    1.56 +Constructor for the WINS shared chunk record PDD.
    1.57 +This function is always executed in driver thread context.
    1.58 +*/
    1.59 +DWinsSoundScRxPdd::DWinsSoundScRxPdd()
    1.60 +	: iDfc(DWinsSoundScRxPdd::RecordDfc,this,2)
    1.61 +	{		
    1.62 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::DWinsSoundScRxPdd"));
    1.63 +	
    1.64 +//	iDriverThreadSem=0;
    1.65 +//	iRecordThread=0;
    1.66 +//	iRecordThreadMutex=0;
    1.67 +//	iRecordThreadSem=0;
    1.68 +//	iStopSemaphore=0;
    1.69 +//	iDeathSemaphore=0;
    1.70 +//	iRecordDeviceHandle=0;
    1.71 +//	iRecordCommand=ERecData;
    1.72 +//	iRecordCommandArg0=0;
    1.73 +//	iRecordCommandArg1=0;
    1.74 +//	iPendingRecord=0;
    1.75 +//	iRecordThreadError=0;
    1.76 +///	iWaveformBufMgr=NULL;
    1.77 +//	iCompletedRecordBufHdrMask=0;
    1.78 +//	iRecordBufferSize=0;
    1.79 +//	iRecordEnabled=EFalse;
    1.80 +//	iNoHardware=EFalse;
    1.81 +//	iRecordTimerEvent=0;
    1.82 +//	iTimerID=0;
    1.83 +//	iTimerActive=EFalse;
    1.84 +	}
    1.85 +	
    1.86 +/**
    1.87 +Destructor for the WINS shared chunk record PDD.
    1.88 +This function is always executed in driver thread context.
    1.89 +*/
    1.90 +DWinsSoundScRxPdd::~DWinsSoundScRxPdd()
    1.91 +	{
    1.92 +	// If the Windows thread started up successfully, signal it to shut down and wait for it to do so
    1.93 +	if (iRecordThreadRunning)
    1.94 +		{
    1.95 +		// Signal the windows thread to close down the record device and exit the windows thread.
    1.96 +		iDeathSemaphore = CreateSemaphore(NULL, 0, 2, NULL);
    1.97 +		RecordThreadCommand(EExit);
    1.98 +	
    1.99 +		// Wait for the record thread to terminate.
   1.100 +		if (iDeathSemaphore)
   1.101 +			{
   1.102 +			Emulator::Escape();
   1.103 +			WaitForSingleObject(iDeathSemaphore, INFINITE); 
   1.104 +			Emulator::Reenter();
   1.105 +
   1.106 +			__HOST_LOCK;
   1.107 +			CloseHandle(iDeathSemaphore);
   1.108 +			}
   1.109 +		}
   1.110 +		
   1.111 +	if (iRecordTimerEvent)
   1.112 +		CloseHandle(iRecordTimerEvent); 
   1.113 +	if (iRecordThreadSem)
   1.114 +		CloseHandle(iRecordThreadSem); 
   1.115 +	if (iRecordThread)
   1.116 +		CloseHandle(iRecordThread);
   1.117 +	if (iDriverThreadSem)
   1.118 +		CloseHandle(iDriverThreadSem); 	
   1.119 +	
   1.120 +	if (iWaveformBufMgr)
   1.121 +		delete iWaveformBufMgr;
   1.122 +	}
   1.123 +	
   1.124 +/**
   1.125 +Second stage constructor for the WINS shared chunk record PDD.
   1.126 +Note that this constructor is called before the second stage constructor for the LDD so it is not
   1.127 +possible to call methods on the LDD here.
   1.128 +This function is always executed in driver thread context.
   1.129 +@param aPhysicalDevice A pointer to the factory class that is creating this PDD.
   1.130 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.131 +*/	
   1.132 +TInt DWinsSoundScRxPdd::DoCreate(DWinsSoundScPddFactory* aPhysicalDevice)
   1.133 +	{
   1.134 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::DoCreate"));
   1.135 +
   1.136 +	iPhysicalDevice=aPhysicalDevice;
   1.137 +	
   1.138 +	// Set up the correct DFC queue.
   1.139 +	iDfc.SetDfcQ(iPhysicalDevice->iDfcQ);
   1.140 +	
   1.141 +	SetCaps();	// Setup the capabilities of this device.
   1.142 +	
   1.143 +	// Setup the default audio configuration
   1.144 +	iSoundConfig.iChannels=2;
   1.145 +	iSoundConfig.iRate=ESoundRate48000Hz;
   1.146 +	iSoundConfig.iEncoding=ESoundEncoding16BitPCM;
   1.147 +	iSoundConfig.iDataFormat=ESoundDataFormatInterleaved;
   1.148 +	
   1.149 +	__HOST_LOCK;
   1.150 +
   1.151 +	// Query the waveform device capabilities using the default device identifier in order
   1.152 +	// to check if there is a functioning waveform device present.  Note that some versions of
   1.153 +	// Windows (such as Windows Server 2003) will actually return MMSYSERR_NOERROR when this is
   1.154 +	// called, even if there is no waveform device present, so we have a further check in
   1.155 +	// when waveInOpen() is called
   1.156 +	WAVEINCAPS waveInCaps;
   1.157 +	MMRESULT res = waveInGetDevCaps(WAVE_MAPPER,&waveInCaps,sizeof(WAVEINCAPS));
   1.158 +#ifdef FORCE_NO_HARDWARE
   1.159 +	res=MMSYSERR_NOERROR+1;
   1.160 +#endif
   1.161 +	if (res != MMSYSERR_NOERROR)
   1.162 +		iNoHardware = ETrue;
   1.163 +	
   1.164 +	__HOST_LOCK_OFF;
   1.165 +	
   1.166 +	// Create the windows waveform audio buffer manager.
   1.167 +	iWaveformBufMgr=new TWaveformBufMgr(ESoundDirRecord,!iNoHardware);
   1.168 +	if (!iWaveformBufMgr)
   1.169 +		return(KErrNoMemory);
   1.170 +	
   1.171 +	// Create the driver thread semaphore.
   1.172 +	iDriverThreadSem = CreateSemaphore(NULL,0,0x7fffffff,NULL);
   1.173 +	if (!iDriverThreadSem)
   1.174 +		return(KErrNoMemory);
   1.175 +	
   1.176 +	// Create the record windows thread.
   1.177 +	if ((iRecordThread=CreateWin32Thread(EThreadEvent,(LPTHREAD_START_ROUTINE)RecordThreadFunction,(void *)this, FALSE))==NULL)
   1.178 +		return(Emulator::LastError());
   1.179 +	SetThreadPriority(iRecordThread,THREAD_PRIORITY_HIGHEST);
   1.180 +	__ASSERT_ALWAYS( ResumeThread(iRecordThread) != 0xffffffff, PANIC()); //Windows Unexpected Error
   1.181 +	
   1.182 +	// Wait to be notified of successful thread initialization
   1.183 +	Emulator::Escape();
   1.184 +	WaitForSingleObject(iDriverThreadSem,INFINITE);
   1.185 +	Emulator::Reenter();
   1.186 +
   1.187 +	// If the Windows thread started up successfully, indicate this fact so that when shutting down we know
   1.188 +	// to signal to the thread to exit
   1.189 +	if (iRecordThreadError == KErrNone)
   1.190 +		iRecordThreadRunning = ETrue;
   1.191 +
   1.192 +	return(iRecordThreadError);
   1.193 +	}
   1.194 +
   1.195 +/**
   1.196 +Called from the LDD to return the DFC queue to be used by this device.
   1.197 +This function is always executed in driver thread context.
   1.198 +@return The DFC queue to use.
   1.199 +*/	
   1.200 +TDfcQue* DWinsSoundScRxPdd::DfcQ(TInt /*aUnit*/)
   1.201 +	{
   1.202 +	return(iPhysicalDevice->iDfcQ);
   1.203 +	}
   1.204 +
   1.205 +/** 
   1.206 +Called from the LDD to return the shared chunk create information to be used by this device.
   1.207 +This function is always executed in driver thread context.
   1.208 +@param aChunkCreateInfo A chunk create info. object to be to be filled with the settings
   1.209 +						required for this device.
   1.210 +*/		
   1.211 +void DWinsSoundScRxPdd::GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo)
   1.212 +	{
   1.213 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::GetChunkCreateInfo"));
   1.214 +
   1.215 +	aChunkCreateInfo.iType=TChunkCreateInfo::ESharedKernelMultiple;
   1.216 +	aChunkCreateInfo.iMapAttr=0;
   1.217 +	aChunkCreateInfo.iOwnsMemory=ETrue; 				// Using RAM pages.
   1.218 +	aChunkCreateInfo.iDestroyedDfc=NULL; 				// No chunk destroy DFC.
   1.219 +	}
   1.220 +	
   1.221 +/**
   1.222 +Called from the LDD to return the capabilities of this device.
   1.223 +This function is always executed in driver thread context.
   1.224 +@param aCapsBuf A packaged TSoundFormatsSupportedV02 object to be filled with the record
   1.225 +				capabilities of this device. This descriptor is in kernel memory and can be accessed directly.
   1.226 +@see TSoundFormatsSupportedV02.
   1.227 +*/
   1.228 +void DWinsSoundScRxPdd::Caps(TDes8& aCapsBuf) const
   1.229 +	{
   1.230 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::Caps"));
   1.231 +	
   1.232 +	// Copy iCaps back.
   1.233 +	TPtrC8 ptr((const TUint8*)&iCaps,sizeof(iCaps));
   1.234 +	aCapsBuf.FillZ(aCapsBuf.MaxLength());
   1.235 +	aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength()));	
   1.236 +	}
   1.237 +	
   1.238 +/**
   1.239 +Called from the LDD to return the maximum transfer length in bytes that this device can support in a single data transfer.
   1.240 +@return The maximum transfer length in bytes.
   1.241 +*/
   1.242 +TInt DWinsSoundScRxPdd::MaxTransferLen() const
   1.243 +	{
   1.244 +	return(KWinsMaxAudioTransferLen);		// 32K
   1.245 +	}		
   1.246 +				
   1.247 +/**
   1.248 +Called from the LDD to power up the sound device.
   1.249 +This function is always executed in driver thread context.
   1.250 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.251 +*/
   1.252 +TInt DWinsSoundScRxPdd::PowerUp()
   1.253 +	{
   1.254 +	return(KErrNone);
   1.255 +	}
   1.256 +
   1.257 +/**
   1.258 +Called from the LDD to configure or reconfigure the device using the the configuration supplied.
   1.259 +This function is always executed in driver thread context.
   1.260 +@param aConfigBuf A packaged TCurrentSoundFormatV02 object which contains the new configuration settings.
   1.261 +				  This descriptor is in kernel memory and can be accessed directly.
   1.262 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.263 +@see TCurrentSoundFormatV02.
   1.264 +*/	
   1.265 +TInt DWinsSoundScRxPdd::SetConfig(const TDesC8& aConfigBuf)
   1.266 +	{
   1.267 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::SetConfig"));
   1.268 +
   1.269 +	// Cannot change the configuration while the device is open and recording. (LDD should prevent
   1.270 +	// this anyway but better safe than sorry).
   1.271 +	if (iRecordDeviceHandle)
   1.272 +		return(KErrInUse);
   1.273 +	
   1.274 +	// Save the current settings so we can restore them if there is a problem with the new ones.
   1.275 +	TCurrentSoundFormatV02 saved=iSoundConfig;
   1.276 +	
   1.277 +	// Read the new configuration from the LDD.
   1.278 +	TPtr8 ptr((TUint8*)&iSoundConfig,sizeof(iSoundConfig));
   1.279 +	Kern::InfoCopy(ptr,aConfigBuf);
   1.280 +	
   1.281 +	// Open the record device with the new settings to check they are supported. Then close it
   1.282 +	// again - don't leave it open yet.
   1.283 +	TInt r = CreateRecordDevice(ETrue);
   1.284 +	if (r==KErrNone)
   1.285 +		CloseRecordDevice();
   1.286 +	else
   1.287 +		iSoundConfig=saved;	// Restore the previous settings
   1.288 +	
   1.289 +	return(r);
   1.290 +	}
   1.291 +
   1.292 +/**
   1.293 +Called from the LDD to set the record level.
   1.294 +This function is always executed in driver thread context.
   1.295 +@param aLevel The record level to be set - a value in the range 0 to 255. The value 255 equates 
   1.296 +	   to the maximum record level and each value below this equates to a 0.5dB step below it.
   1.297 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.298 +*/
   1.299 +TInt DWinsSoundScRxPdd::SetVolume(TInt /*aVolume*/)
   1.300 +	{
   1.301 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::SetVolume"));
   1.302 +	
   1.303 +	// There's no adjustment of the record level on the wave in device.
   1.304 +	
   1.305 +	return(KErrNone);
   1.306 +	}
   1.307 +	
   1.308 +/**
   1.309 +Called from the LDD to prepare the audio device for recording.
   1.310 +This function is always executed in driver thread context.
   1.311 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.312 +*/
   1.313 +TInt DWinsSoundScRxPdd::StartTransfer()
   1.314 +	{
   1.315 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::StartTransfer"));
   1.316 +
   1.317 +	// Convert the enum representing the current sample rate into an integer
   1.318 +	TInt samplesPerSecond=RateInSamplesPerSecond(iSoundConfig.iRate);
   1.319 +	if (samplesPerSecond==0)
   1.320 +		return(KErrNotSupported);
   1.321 +
   1.322 +	// Now convert the sample rate into the number of bytes per second and save for later use
   1.323 +	iBytesPerSecond=samplesPerSecond;
   1.324 +	if (iSoundConfig.iChannels==2)
   1.325 +		iBytesPerSecond*=2;
   1.326 +	if (iSoundConfig.iEncoding==ESoundEncoding16BitPCM)
   1.327 +		iBytesPerSecond*=2;
   1.328 +
   1.329 +	iBytesRecordedBeforeLastPause = 0;
   1.330 +	iBytesSincePauseReportedToLdd = 0;
   1.331 +
   1.332 +	iRecordEnabled=ETrue;
   1.333 +
   1.334 +	// Open the record device with the current settings.
   1.335 +	iPendingRecord=0;
   1.336 +	iCompletedRecordBufHdrMask=0;					// Reset the completion status mask
   1.337 +	TInt r = CreateRecordDevice();
   1.338 +	return(r);
   1.339 +	}
   1.340 +	
   1.341 +/**
   1.342 +Called from the LDD to initiate the recording of a portion of data from the audio device. 
   1.343 +When the transfer is complete, the PDD signals this event using the LDD function RecordCallback().
   1.344 +This function is always executed in driver thread context.
   1.345 +@param aTransferID A value assigned by the LDD to allow it to uniquely identify a particular transfer fragment.
   1.346 +@param aLinAddr The linear address within the shared chunk for storing the recorded data.
   1.347 +@param aPhysAddr The physical address within the shared chunk for storing the recorded data.
   1.348 +@param aNumBytes The number of bytes to be recorded. 
   1.349 +@return KErrNone if the transfer has been initiated successfully;
   1.350 +  		KErrNotReady if the device is unable to accept the transfer for the moment;
   1.351 +		otherwise one of the other system-wide error codes.
   1.352 +*/
   1.353 +TInt DWinsSoundScRxPdd::TransferData(TUint aTransferID,TLinAddr aLinAddr,TPhysAddr /*aPhysAddr*/,TInt aNumBytes)
   1.354 +	{
   1.355 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::TransferData(ID:%xH)",aTransferID));
   1.356 +	
   1.357 +	// Check that we can accept the request
   1.358 +	if (aNumBytes>KWinsMaxAudioTransferLen)
   1.359 +		return(KErrArgument);
   1.360 +	if (iPendingRecord>=iWaveformBufMgr->iNumWaveformBufs)	// LDD may issue multiple data transfers per buffer.
   1.361 +		return(KErrNotReady);
   1.362 +	
   1.363 +	// Signal the windows thread to initiate the recording of a buffers worth of data from the wavein device.
   1.364 +	iPendingRecord++;
   1.365 +	RecordThreadCommand(ERecData,aTransferID,aLinAddr,aNumBytes);
   1.366 +	
   1.367 +	// Although the windows thread runs at a higher priority, its not safe to assume we will always get pre-empted at this
   1.368 +	// point while the the higher priority thread processes and completes the request. Instead we need to wait until it
   1.369 +	// signals back completion of the command.
   1.370 +	Emulator::Escape();
   1.371 +	WaitForSingleObject(iDriverThreadSem,INFINITE);
   1.372 +	Emulator::Reenter();	
   1.373 +
   1.374 +	return(iRecordThreadError);	
   1.375 +	}
   1.376 +
   1.377 +/**
   1.378 +Called from the LDD to terminate the recording of a data from the device and to release any resources necessary for
   1.379 +recording.
   1.380 +The LDD will leave the audio device capturing record data even when there are no record requests pending from the client.
   1.381 +Transfer will only be terminated when the client either issues RSoundSc::CancelRecordData() or closes the channel. Once
   1.382 +this function had been called, the LDD will not issue  any further TransferData() commands without first issueing a
   1.383 +StartTransfer() command.
   1.384 +This function is always executed in driver thread context.
   1.385 +*/
   1.386 +void DWinsSoundScRxPdd::StopTransfer()
   1.387 +	{
   1.388 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::StopTransfer"));
   1.389 +	
   1.390 +	// Signal the windows thread to stop it from sending any more buffers to wavein device.
   1.391 +	iStopSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
   1.392 +	RecordThreadCommand(EStop);
   1.393 +
   1.394 +	// Need to wait for the record thread to finish using the record handle before it's safe to close the device and 
   1.395 +	// set the handle to NULL.
   1.396 +	if (iStopSemaphore)
   1.397 +		{
   1.398 +		// Wait for the record thread to stop.
   1.399 +		Emulator::Escape();
   1.400 +		WaitForSingleObject(iStopSemaphore, INFINITE);  
   1.401 +		Emulator::Reenter();
   1.402 +
   1.403 +		__HOST_LOCK;
   1.404 +		CloseHandle(iStopSemaphore);
   1.405 +		iStopSemaphore = NULL;
   1.406 +		}
   1.407 +		
   1.408 +	// Make sure the DFC is not queued.
   1.409 +	iDfc.Cancel();	
   1.410 +			
   1.411 +	CloseRecordDevice();							// Close down the record device.
   1.412 +	iPendingRecord=0;
   1.413 +	iCompletedRecordBufHdrMask=0;					// Reset the completion status mask
   1.414 +	}
   1.415 +
   1.416 +/**
   1.417 +Called from the LDD to halt the recording of data from the sound device but not to release any resources necessary for
   1.418 +recording.
   1.419 +All active transfers should be aborted. When recording is halted the PDD signals this event with a single call of the LDD 
   1.420 +function RecordCallback() - reporting back any partial data already received. If transfer is resumed later, the LDD will
   1.421 +issue a new TransferData() request to re-commence data transfer.
   1.422 +This function is always executed in driver thread context.
   1.423 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.424 +*/
   1.425 +TInt DWinsSoundScRxPdd::PauseTransfer()
   1.426 +	{
   1.427 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::PauseTransfer"));
   1.428 +	
   1.429 +	// Signal the windows thread to stop recording on the wavein device - aborting any transfers queued.
   1.430 +	RecordThreadCommand(EPause);
   1.431 +	
   1.432 +	// Wait for the windows thread to complete the request
   1.433 +	Emulator::Escape();
   1.434 +	WaitForSingleObject(iDriverThreadSem,INFINITE);
   1.435 +	Emulator::Reenter();
   1.436 +	
   1.437 +	// Make sure the DFC is not queued.
   1.438 +	iDfc.Cancel();
   1.439 +	
   1.440 +	// The windows thread returns the total bytes recorded since the last pause (as reported by windows). 
   1.441 +	TUint totalRecordedSincePause = iRecordThreadError;
   1.442 +	TUint lastTransferLength = totalRecordedSincePause - iBytesSincePauseReportedToLdd;
   1.443 +	Kern::Printf("totalRecordedSincePause %d - iBytesSincePauseReportedToLdd %d = lastTransferLength %d\n",
   1.444 +				 totalRecordedSincePause, iBytesSincePauseReportedToLdd, lastTransferLength);
   1.445 +
   1.446 +	iBytesRecordedBeforeLastPause += totalRecordedSincePause;
   1.447 +	iBytesSincePauseReportedToLdd = 0;
   1.448 +
   1.449 +	if (iPendingRecord)
   1.450 +		{
   1.451 +		Ldd()->RecordCallback(0, KErrNone, lastTransferLength);	// We can use a NULL tranfer ID when pausing.
   1.452 +	
   1.453 +		// The LDD will abandon any other transfers queued so we can mark all buffers as not in use.
   1.454 +    	for (TInt i=0 ; i<iWaveformBufMgr->iNumWaveformBufs ; i++)
   1.455 +    		{
   1.456 +    		TWaveformAudioBuf* buf=&iWaveformBufMgr->iWaveformAudioBuf[i];
   1.457 +    		if (buf->iIsInUse)
   1.458 +    			buf->iIsInUse=EFalse;
   1.459 +    		}
   1.460 +		iPendingRecord=0;
   1.461 +		}
   1.462 +
   1.463 +	// Indicate that all request to Windows for recording have been cancelled
   1.464 +	iCompletedRecordBufHdrMask=0;
   1.465 +					
   1.466 +	return(KErrNone);
   1.467 +	}
   1.468 +	
   1.469 +/**
   1.470 +Called from the LDD to resume the recording of data from the sound device following a request to halt recording.
   1.471 +Any active transfer would have been aborted when the device was halted so its just a case of re-creating the same setup
   1.472 +acheived following StartTransfer().
   1.473 +This function is always executed in driver thread context.
   1.474 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.475 +*/
   1.476 +TInt DWinsSoundScRxPdd::ResumeTransfer()
   1.477 +	{
   1.478 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::ResumeTransfer"));
   1.479 +	
   1.480 +	iPendingRecord=0;
   1.481 +	iCompletedRecordBufHdrMask=0; // All buffers would have completed during pausing (waveInReset) so clear mask.
   1.482 +	iRecordEnabled=ETrue; // Simply set the flag to enable the windows thread to restart sending buffers to wavein device. 
   1.483 +
   1.484 +	// Signal the windows thread to resume recording on the wavein device.
   1.485 +	RecordThreadCommand(EResume);
   1.486 +
   1.487 +	return(KErrNone);
   1.488 +	}
   1.489 +	
   1.490 +/**
   1.491 +Called from the LDD to power down the sound device.
   1.492 +This function is always executed in driver thread context.
   1.493 +*/
   1.494 +void DWinsSoundScRxPdd::PowerDown()
   1.495 +	{
   1.496 +	
   1.497 +	}
   1.498 +	
   1.499 +/**
   1.500 +Called from the LDD to handle a custom configuration request.
   1.501 +@param aFunction A number identifying the request.
   1.502 +@param aParam A 32-bit value passed to the driver. Its meaning depends on the request.
   1.503 +@return KErrNone if successful, otherwise one of the other system wide error codes.
   1.504 +*/
   1.505 +TInt DWinsSoundScRxPdd::CustomConfig(TInt /*aFunction*/,TAny* /*aParam*/)
   1.506 +	{
   1.507 +	return(KErrNotSupported);
   1.508 +	}
   1.509 +		
   1.510 +/**
   1.511 +Called from the LDD to find out how many microseconds of data have been recorded.  This is called
   1.512 +in the context of the DFC thread.
   1.513 +@param aTimeTransferred	A reference to a variable into which to place the number of microseconds of audio.
   1.514 +@param aStatus			The current status of this channel
   1.515 +@return KErrNone if time is valid or KErrNotSupported.
   1.516 +*/
   1.517 +TInt DWinsSoundScRxPdd::TimeTransferred(TInt64& aTimeRecorded, TInt aState)
   1.518 +	{
   1.519 +	TInt r=KErrGeneral;
   1.520 +	TInt64 ms=0;
   1.521 +
   1.522 +	if(iRecordDeviceHandle == 0)
   1.523 +		{
   1.524 +		// Recording not started yet
   1.525 +		aTimeRecorded = 0;
   1.526 +		return KErrNone;
   1.527 +		}
   1.528 +
   1.529 +	// Kern::Printf("DWinsSoundScRxPdd::TimeTransferred - (iBytesSincePauseReportedToLdd=%d)\n", iBytesSincePauseReportedToLdd);
   1.530 +	if (aState == DSoundScLdd::EPaused)
   1.531 +		{
   1.532 +		// Kern::Printf("DWinsSoundScRxPdd::TimeTransferred (paused) - iBytesRecordedBeforeLastPause %d\n", iBytesRecordedBeforeLastPause);
   1.533 +		// Just use the paused number of bytes
   1.534 +		ms=((iBytesRecordedBeforeLastPause/iBytesPerSecond)*1000);
   1.535 +		TUint remainder=(iBytesRecordedBeforeLastPause%iBytesPerSecond);
   1.536 +		ms+=((remainder*1000)/iBytesPerSecond);
   1.537 +		ms*=1000;
   1.538 +		aTimeRecorded=ms;
   1.539 +		r=KErrNone;
   1.540 +		}
   1.541 +
   1.542 +	TInt64 bytesTransferredSincePause = 0;
   1.543 +	// If no hardware is present then we need to use iBytesSincePauseReportedToLdd + a fudge factor to allow
   1.544 +	// the number of bytes processed by the "hardware" within the current transfer.
   1.545 +	if(iNoHardware)
   1.546 +		{
   1.547 +		// Determine the # of milliseconds that have passed since the last timer triggered
   1.548 +		DWORD currentTime = timeGetTime();
   1.549 +		DWORD timeSinceLastEvent = (currentTime - iLastTimerEventTime);
   1.550 +
   1.551 +		// Clamp the resulting value to the duration of the timer, to prevent the millisecond count
   1.552 +		// going backwards if Windows is busy and latency becomes an issue
   1.553 +		if (timeSinceLastEvent > iSimulatedMsecDuration)
   1.554 +			timeSinceLastEvent = iSimulatedMsecDuration;
   1.555 +
   1.556 +		bytesTransferredSincePause = iBytesSincePauseReportedToLdd;
   1.557 +		WAVEHDR *buf = iWaveformBufMgr->iPendingBufList[0];
   1.558 +		if(buf)
   1.559 +			{
   1.560 +			// Add on an estimate of the progress of the current transfer
   1.561 +			bytesTransferredSincePause += ((buf->dwBufferLength * timeSinceLastEvent) / iSimulatedMsecDuration);
   1.562 +			}
   1.563 +		}
   1.564 +	else
   1.565 +		{
   1.566 +		// Get the number of bytes recorded by the Windows audio system
   1.567 +		MMTIME time;
   1.568 +		time.wType=TIME_BYTES;
   1.569 +		if ((waveInGetPosition(iRecordDeviceHandle,&time,sizeof(time)) != MMSYSERR_NOERROR) ||
   1.570 +			(time.wType != TIME_BYTES))
   1.571 +			{
   1.572 +			// If requesting the number of bytes recorded is not supported, wType will be
   1.573 +			// changed to what was actually returned, so check for this and don't continue
   1.574 +			// if we got anything other than bytes
   1.575 +			return KErrNotSupported;
   1.576 +			}
   1.577 +		bytesTransferredSincePause = time.u.cb;
   1.578 +		}
   1.579 +
   1.580 +	// Kern::Printf("DWinsSoundScRxPdd::TimeTransferred - iBytesRecordedBeforeLastPause %d + bytesTransferredSincePause %d total %d (iNoHardware %d)\n", 
   1.581 +	// 			iBytesRecordedBeforeLastPause, TUint32(bytesTransferredSincePause), TUint32(bytesTransferredSincePause + iBytesRecordedBeforeLastPause), iNoHardware);
   1.582 +	// Convert the number of bytes recorded into microseconds and return it
   1.583 +	ms=(((bytesTransferredSincePause + iBytesRecordedBeforeLastPause)/iBytesPerSecond)*1000);
   1.584 +	TUint64 remainder=((bytesTransferredSincePause + iBytesRecordedBeforeLastPause)%iBytesPerSecond);
   1.585 +	ms+=((remainder*1000)/iBytesPerSecond);
   1.586 +	ms*=1000;
   1.587 +	aTimeRecorded=ms;
   1.588 +	r=KErrNone;
   1.589 +
   1.590 +	return(r);
   1.591 +	}
   1.592 +
   1.593 +/** 
   1.594 +Prepare the waveform audio buffer for record.
   1.595 +@param aRecordDeviceHandle The handle to the waveform audio input device.
   1.596 +*/		
   1.597 +void TWaveformAudioBuf::DoPrepareIn(HWAVEIN aRecordDeviceHandle)
   1.598 +	{
   1.599 +	MMRESULT res = waveInPrepareHeader(aRecordDeviceHandle,&iBufHdr,sizeof(WAVEHDR));
   1.600 +	__KTRACE_SND(Kern::Printf("   waveInPrepareHeader(BufNo:%d Pos:%x Len:%d)-%d",iBufNum,iBufHdr.lpData,iBufHdr.dwBufferLength,res));
   1.601 +	__ASSERT_ALWAYS(res==MMSYSERR_NOERROR,Kern::Fault("DWinsSoundScTxPddWIPH", res)); //WaveInPrepareHeader error.	
   1.602 +	}
   1.603 +	
   1.604 +/**
   1.605 +Cleanup the preparation performed when the waveform audio buffer was prepared for record.
   1.606 +@param aRecordDeviceHandle The handle to the waveform audio input device.
   1.607 +*/	
   1.608 +void TWaveformAudioBuf::DoUnprepareIn(HWAVEIN aRecordDeviceHandle)
   1.609 +	{
   1.610 +	MMRESULT res = waveInUnprepareHeader(aRecordDeviceHandle,&iBufHdr,sizeof(WAVEHDR));
   1.611 +	__KTRACE_SND(Kern::Printf("   waveInUnprepareHeader(BufNo:%d)-%d",iBufNum,res));
   1.612 +	__ASSERT_ALWAYS(res==MMSYSERR_NOERROR,Kern::Fault("DWinsSoundScTxPddWIUH",res)); //WaveInUnprepareHeader error.
   1.613 +	}
   1.614 +															
   1.615 +/**
   1.616 +The waveform input callback function to handle data block transfer completion.
   1.617 +This function is always executed in windows thread context.
   1.618 +@param aHdr A pointer to the header for the waveform audio buffer just transferred.
   1.619 +*/	
   1.620 +void DWinsSoundScRxPdd::WaveInProc(WAVEHDR* aHdr)
   1.621 +	{
   1.622 +	TInt waveBufId=aHdr->dwUser;				// Work out which waveform audio buffer is completing.
   1.623 +    // Kern::Printf("DWinsSoundScRxPdd::WaveInProc waveBufId %d", waveBufId);
   1.624 +
   1.625 +	StartOfInterrupt();
   1.626 +	iCompletedRecordBufHdrMask|=(1<<waveBufId);	// Update the completion status mask
   1.627 +	iDfc.Add();									// Queue RecordDfc().
   1.628 +	EndOfInterrupt();
   1.629 +	}
   1.630 +	
   1.631 +/**
   1.632 +The DFC used to handle data block record completion.
   1.633 +This function is always executed in driver thread context.
   1.634 +@param aPtr A pointer to the physical channel object.
   1.635 +*/	
   1.636 +void DWinsSoundScRxPdd::RecordDfc(TAny* aPtr)
   1.637 +	{
   1.638 +	TInt i;
   1.639 +	DWinsSoundScRxPdd& drv=*(DWinsSoundScRxPdd*)aPtr;
   1.640 +	
   1.641 +	// More than 1 transfer may have completed so loop until all completions are handled
   1.642 +	while (drv.iCompletedRecordBufHdrMask)
   1.643 +		{
   1.644 +		// Find the buffer ID of the next transfer that has completed
   1.645 +		for (i=0 ; i<32 && !(drv.iCompletedRecordBufHdrMask&(1<<i)) ; i++) {}
   1.646 +		__ASSERT_ALWAYS(i<drv.iWaveformBufMgr->iNumWaveformBufs,PANIC());
   1.647 +		__e32_atomic_and_ord32(&drv.iCompletedRecordBufHdrMask, ~(1u<<i)); // Clear this bit in the mask
   1.648 +		
   1.649 +		// Update the status of the waveform audio buffer which is completing
   1.650 +		TWaveformAudioBuf& buf=drv.iWaveformBufMgr->iWaveformAudioBuf[i];
   1.651 +		buf.iIsInUse=EFalse;
   1.652 +	
   1.653 +		// Callback the LDD passing the information for the transfer that has completed
   1.654 +		drv.iPendingRecord--;
   1.655 +		__KTRACE_SND(Kern::Printf("   Read complete(BufNo:%x Pos:%x Len:%d)",i,buf.iBufHdr.lpData,buf.iBufHdr.dwBufferLength));
   1.656 +		drv.iBytesSincePauseReportedToLdd += buf.iBufHdr.dwBufferLength;
   1.657 +		drv.Ldd()->RecordCallback(buf.iTransferID,KErrNone,buf.iBufHdr.dwBufferLength);
   1.658 +		}
   1.659 +	}	
   1.660 +
   1.661 +/**
   1.662 +Issue a request from the driver thread to the windows thread to execute a command.
   1.663 +@param aCommand The identifier of the command to be executed.
   1.664 +@param aArg0 A first command argument, its meaning depends on the command.
   1.665 +@param aArg1 A second command argument, its meaning depends on the command.
   1.666 +@param aArg2 A third command argument, its meaning depends on the command.
   1.667 +This function is always executed in driver thread context.
   1.668 +*/
   1.669 +void DWinsSoundScRxPdd::RecordThreadCommand(TThreadCommand aCommand,TInt aArg0,TInt aArg1,TInt aArg2)
   1.670 +	{
   1.671 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd:RecordThreadCommand"));
   1.672 +	iRecordCommand = aCommand;
   1.673 +	iRecordCommandArg0 = aArg0;
   1.674 +	iRecordCommandArg1 = aArg1;
   1.675 +	iRecordCommandArg2 = aArg2;
   1.676 +
   1.677 +	__HOST_LOCK;
   1.678 +
   1.679 +	ReleaseSemaphore(iRecordThreadSem,1,NULL);
   1.680 +	}
   1.681 +
   1.682 +/**
   1.683 +Pass a value from the windows thread to the driver thread.
   1.684 +This function is always executed in windows thread context.
   1.685 +@param aError The value to the passed to the driver thread.
   1.686 +*/
   1.687 +void DWinsSoundScRxPdd::RecordThreadNotifyDriver(TInt aError)
   1.688 +	{
   1.689 +	iRecordThreadError = aError;
   1.690 +	BOOL ret = ReleaseSemaphore(iDriverThreadSem,1,NULL);
   1.691 +	__ASSERT_ALWAYS(ret == TRUE,PANIC()); //Unexpected Windows Error
   1.692 +	}
   1.693 +
   1.694 +#pragma warning(disable : 4702) // unreachable code
   1.695 +/**
   1.696 +Open the waveform input device for record. Use a default device identifier in order to select a device
   1.697 +capable of meeting the current audio configuration. 
   1.698 +This function can be executed in either driver thread or windows thread context.
   1.699 +@pre The data member DWinsSoundScRxPdd::iSoundConfig must be setup with the current audio configuration.
   1.700 +*/
   1.701 +TInt DWinsSoundScRxPdd::OpenWaveInDevice()
   1.702 +	{
   1.703 +	WAVEFORMATEX format;
   1.704 +	format.wFormatTag = WAVE_FORMAT_PCM;
   1.705 +	TUint16 bitsPerSample = 8;
   1.706 +
   1.707 +	switch (iSoundConfig.iEncoding)
   1.708 +		{
   1.709 +		case ESoundEncoding8BitPCM:
   1.710 +			break;
   1.711 +		case ESoundEncoding16BitPCM:
   1.712 +			bitsPerSample = 16;
   1.713 +			break;
   1.714 +		default:
   1.715 +			return KErrNotSupported;
   1.716 +		};
   1.717 +
   1.718 +	TInt rateInSamplesPerSecond=RateInSamplesPerSecond(iSoundConfig.iRate);
   1.719 +	format.nChannels = TUint16(iSoundConfig.iChannels);
   1.720 +	format.nSamplesPerSec = rateInSamplesPerSecond;
   1.721 +	format.nAvgBytesPerSec = rateInSamplesPerSecond * iSoundConfig.iChannels * bitsPerSample / 8;
   1.722 +	format.nBlockAlign = TUint16(iSoundConfig.iChannels * bitsPerSample / 8);
   1.723 +	format.wBitsPerSample = bitsPerSample;
   1.724 +	format.cbSize = 0;
   1.725 +
   1.726 +	MMRESULT res = MMSYSERR_NOERROR;
   1.727 +
   1.728 +	__COND_HOST_LOCK;		
   1.729 +	if (iNoHardware)
   1.730 +		{
   1.731 +		timeBeginPeriod(KMMTimerRes);
   1.732 +		iRecordDeviceHandle = (HWAVEIN)1;	
   1.733 +		}
   1.734 +	else
   1.735 +		{
   1.736 +		res = waveInOpen(&iRecordDeviceHandle, WAVE_MAPPER, &format, (DWORD)::WaveInProc, (DWORD)this, CALLBACK_FUNCTION);
   1.737 +
   1.738 +		// On some builds of Windows (such as Windows Server 2003), the waveInGetDevCaps() trick in
   1.739 +		// DoCreate() won't work, so we have another special check for missing hardware here
   1.740 +		if ((res == MMSYSERR_NODRIVER) || (res == MMSYSERR_BADDEVICEID))
   1.741 +			{
   1.742 +			// Pretend there was no error and switch into hardware emulation mode
   1.743 +			res = MMSYSERR_NOERROR;
   1.744 +			iNoHardware = ETrue;
   1.745 +			iRecordDeviceHandle = (HWAVEIN)1;	
   1.746 +			iWaveformBufMgr->iIsHardware = EFalse;
   1.747 +			timeBeginPeriod(KMMTimerRes);
   1.748 +			}
   1.749 +		}
   1.750 +
   1.751 +	switch (res)
   1.752 +		{
   1.753 +		case MMSYSERR_NOERROR: // No error
   1.754 +			return(KErrNone);
   1.755 +		case MMSYSERR_ALLOCATED: // Specified resource is already allocated.
   1.756 +			return(KErrInUse);
   1.757 +		case WAVERR_BADFORMAT: // Attempted to open with an unsupported waveform-audio format
   1.758 +			return(KErrNotSupported);
   1.759 +		case MMSYSERR_NOMEM: // Unable to allocate or lock memory.
   1.760 +			return(KErrNoMemory);
   1.761 +		default:
   1.762 +			return(KErrUnknown);
   1.763 +		}
   1.764 +	}
   1.765 +#pragma warning(default : 4702) // unreachable code
   1.766 +
   1.767 +/**
   1.768 +Open the audio input device.
   1.769 +This function is always executed in driver thread context.
   1.770 +@pre The data members DWinsSoundScRxPdd::iSoundConfig must be setup with the current audio configuration.
   1.771 +*/
   1.772 +TInt DWinsSoundScRxPdd::CreateRecordDevice(TBool aCheckDevice)
   1.773 +	{
   1.774 +	// Check if the waveform input device is already open.
   1.775 +	if (iRecordDeviceHandle)
   1.776 +		return(KErrNone);
   1.777 +
   1.778 +	__HOST_LOCK;
   1.779 +
   1.780 +	// Open the waveform input device for recording.
   1.781 +	TInt err = OpenWaveInDevice();
   1.782 +	if (err != KErrNone)
   1.783 +		return(err);
   1.784 +	
   1.785 +	__HOST_LOCK_OFF;	
   1.786 +
   1.787 +	if (!aCheckDevice)
   1.788 +		{
   1.789 +		// Now, re-allocate a set of the waveform audio blocks in advance of any recording. Also, prepare one of these
   1.790 +		// for each buffer within the shared chunk. Need to be in critical section while re-allocating the audio blocks.
   1.791 +		NKern::ThreadEnterCS();
   1.792 +		err=iWaveformBufMgr->ReAllocAndUpdate(Ldd()->BufConfig(),Ldd()->ChunkBase(),(TInt)iRecordDeviceHandle);
   1.793 +		NKern::ThreadLeaveCS(); 
   1.794 +		}
   1.795 +		
   1.796 +	return(err);
   1.797 +	}
   1.798 +
   1.799 +/**
   1.800 +Close down the record device.
   1.801 +This function is always executed in driver thread context.
   1.802 +*/
   1.803 +void DWinsSoundScRxPdd::CloseRecordDevice()
   1.804 +	{
   1.805 +	__COND_HOST_LOCK;
   1.806 +
   1.807 +	if (iNoHardware)
   1.808 +		timeEndPeriod(KMMTimerRes);
   1.809 +
   1.810 +	HWAVEIN handle = iRecordDeviceHandle;
   1.811 +
   1.812 +	if (handle)
   1.813 +		{
   1.814 +		if (!iNoHardware)
   1.815 +			waveInReset(handle);		// Stop recording.
   1.816 +		
   1.817 +		// Un-prepare all the waveform audio buffers.
   1.818 +		for (TInt i=0 ; i<iWaveformBufMgr->iNumWaveformBufs ; i++)
   1.819 +			iWaveformBufMgr->iWaveformAudioBuf[i].Unprepare((TInt)handle);
   1.820 +		
   1.821 +		if (!iNoHardware)
   1.822 +			waveInClose(handle);		// Close the wavein device.
   1.823 +		
   1.824 +		iRecordDeviceHandle = NULL;
   1.825 +		}
   1.826 +	}
   1.827 +		
   1.828 +/**
   1.829 +The thread function for the record windows thread.
   1.830 +This function is always executed in windows thread context.
   1.831 +@pre The data members DWinsSoundScRxPdd::iSoundConfig must be setup with the current audio configuration.
   1.832 +*/
   1.833 +void DWinsSoundScRxPdd::RecordThread()
   1.834 +	{
   1.835 +	iRecordThreadSem = CreateSemaphore(NULL,0,0x7fffffff,NULL);
   1.836 +	__ASSERT_ALWAYS(iRecordThreadSem,PANIC()); //No Windows Memory
   1.837 +	iRecordTimerEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
   1.838 +	HANDLE objects[2];
   1.839 +	objects[0]=iRecordThreadSem;		// Indicates command from driver thread
   1.840 +	objects[1]=iRecordTimerEvent;
   1.841 +
   1.842 +	// Signal driver of successful setup
   1.843 +	RecordThreadNotifyDriver(KErrNone);
   1.844 +	ResetEvent(iRecordTimerEvent);
   1.845 +	FOREVER
   1.846 +		{
   1.847 +		DWORD ret=WaitForMultipleObjectsEx(2,objects,FALSE,INFINITE,TRUE);
   1.848 +
   1.849 +		switch (ret)
   1.850 +			{
   1.851 +			case WAIT_OBJECT_0:	// Command received from the driver thread.
   1.852 +				if (ProcessRecordCommand(iRecordCommand,iRecordCommandArg0,iRecordCommandArg1,iRecordCommandArg2)==KErrCompletion)
   1.853 +					return; // ********* Exit thread **************
   1.854 +				break;
   1.855 +			case WAIT_OBJECT_0+1:
   1.856 +				HandleRecordTimerEvent();
   1.857 +				break;
   1.858 +			}
   1.859 +		}
   1.860 +	}
   1.861 +	
   1.862 +/**
   1.863 +Process a request from the driver thread to execute a command.
   1.864 +This function is always executed in windows thread context.
   1.865 +@param aCommand The identifier of the command to be executed.
   1.866 +@param aArg0 A first command argument, its meaning depends on the command.
   1.867 +@param aArg1 A second command argument, its meaning depends on the command.
   1.868 +@param aArg2 A third command argument, its meaning depends on the command.
   1.869 +@return KErrCompletion if the command to exit the windows thread has been received;
   1.870 +		KErrNone otherwise;
   1.871 +*/	
   1.872 +TInt DWinsSoundScRxPdd::ProcessRecordCommand(TThreadCommand aCommand,TInt aArg0,TInt aArg1,TInt aArg2)
   1.873 +	{
   1.874 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd:ProcessRecordCommand(%d)",aCommand));
   1.875 +	switch(aCommand)
   1.876 +		{	
   1.877 +		case ERecData:	// Initiate the recording of a buffers worth of data from the wavein device.
   1.878 +			{
   1.879 +			if (iRecordEnabled)
   1.880 +				{
   1.881 +				// Acquire a windows waveform audio buffer for the transfer.
   1.882 +				char* startAddress=(char*)aArg1;
   1.883 +				TInt bytesToRecord=aArg2; 
   1.884 +				__ASSERT_ALWAYS(bytesToRecord>0,PANIC());
   1.885 +				TWaveformAudioBuf* waveformAudioBuf=iWaveformBufMgr->AcquireBuf(startAddress,bytesToRecord,(TInt)iRecordDeviceHandle);
   1.886 +				waveformAudioBuf->iTransferID=(TUint)aArg0;
   1.887 +				waveformAudioBuf->iBufHdr.dwBufferLength=bytesToRecord;
   1.888 +									
   1.889 +				if (!iNoHardware)
   1.890 +					{
   1.891 +					// This machine has a wavein device present. Send the buffer to the wavein device.
   1.892 +					waveInStart(iRecordDeviceHandle); // Start input on the wavein device - safe to call this when already started.
   1.893 +					MMRESULT res = waveInAddBuffer(iRecordDeviceHandle,&waveformAudioBuf->iBufHdr,sizeof(WAVEHDR));
   1.894 +					__KTRACE_SND(Kern::Printf("   waveInAddBuffer(ID:%x Pos:%x Len:%d)-%d",aArg0,startAddress,bytesToRecord,res));
   1.895 +					__ASSERT_ALWAYS(res == MMSYSERR_NOERROR,PANIC());  //WaveInAddBuffer Error
   1.896 +					}
   1.897 +				else	
   1.898 +					{
   1.899 +					// This machine has no audio hardware present so simulate the wavein device using a timer.
   1.900 +					AddToPendingList(&waveformAudioBuf->iBufHdr,iWaveformBufMgr->iPendingBufList); // Queue the buffer on the pending list
   1.901 +				
   1.902 +					// Check if the timer needs starting/re-starting
   1.903 +					if (!iTimerActive)
   1.904 +						{
   1.905 +						iLastTimerEventTime = timeGetTime();
   1.906 +						StartTimer(&waveformAudioBuf->iBufHdr);
   1.907 +						}
   1.908 +					} 			
   1.909 +				}
   1.910 +		
   1.911 +			// Signal the driver thread that we have completed the command.
   1.912 +			RecordThreadNotifyDriver(KErrNone);
   1.913 +			break;
   1.914 +			}
   1.915 +			
   1.916 +			
   1.917 +		case EStop:	// Terminate the recording of data from the wavein device.
   1.918 +			{
   1.919 +			iRecordEnabled=EFalse;	// Stop the windows thread from sending any more buffers to wavein device. 
   1.920 +			
   1.921 +			if (iNoHardware)
   1.922 +				{
   1.923 +				// This machine has no audio hardware present so simulates the waveout device using a timer.
   1.924 +				StopTimer(ETrue);	// Stop the timer and cancel any buffers pending
   1.925 +				}
   1.926 +				
   1.927 +			// Leave the driver thread to close down the record device.
   1.928 +				
   1.929 +			// Signal the driver thread that we have completed the command.	
   1.930 +			if (iStopSemaphore)
   1.931 +				{
   1.932 +				LONG prev;
   1.933 +				ReleaseSemaphore(iStopSemaphore,1,&prev);
   1.934 +				}
   1.935 +			break;
   1.936 +			}
   1.937 +	
   1.938 +		case EExit:	// Close down the record device and exit the windows thread.
   1.939 +			{
   1.940 +			if (!iNoHardware)
   1.941 +				{
   1.942 +				// This machine has a wavein device present.
   1.943 +				if (iRecordDeviceHandle)
   1.944 +					{
   1.945 +					waveInReset(iRecordDeviceHandle);   // Stop recording on the wavein device.
   1.946 +					waveInClose(iRecordDeviceHandle);	// Close the wavein device.
   1.947 +					}
   1.948 +				}
   1.949 +			else
   1.950 +				{
   1.951 +				// This machine has no audio hardware present so simulates the waveout device using a timer.
   1.952 +				StopTimer(ETrue);	// Stop the timer and cancel any buffers pending.
   1.953 +				}	
   1.954 +			// Logically the record device is now shut so clear the handle.
   1.955 +			iRecordDeviceHandle = 0;
   1.956 +	
   1.957 +			// Signal the driver thread that we have completed the command.		
   1.958 +			if (iDeathSemaphore)
   1.959 +				{
   1.960 +				LONG prev;
   1.961 +				ReleaseSemaphore(iDeathSemaphore,1,&prev);
   1.962 +				}
   1.963 +			return(KErrCompletion); 		// ********* Exit thread **************
   1.964 +			}
   1.965 +			
   1.966 +		case EPause:	// Halt the recording of data from the wavein device.
   1.967 +			iRecordEnabled=EFalse;
   1.968 +			
   1.969 +			DWORD position;
   1.970 +			if (!iNoHardware)
   1.971 +				{
   1.972 +				// Need to try to work out how much of the current audio buffer has been filled.
   1.973 +				MMTIME time;
   1.974 +				time.wType = TIME_BYTES;
   1.975 +				HWAVEIN handle = iRecordDeviceHandle;
   1.976 +				waveInGetPosition(handle,&time,sizeof(MMTIME));
   1.977 +				position = time.u.cb;
   1.978 +			
   1.979 +				// Stop recording. (Windows will mark all pending audio buffers as done).
   1.980 +				waveInReset(handle);
   1.981 +				}
   1.982 +			else
   1.983 +				{
   1.984 +				// This machine has no audio hardware present so simulates the waveout device using a timer.
   1.985 +
   1.986 +				// Determine the # of milliseconds that have passed since the last timer triggered
   1.987 +				DWORD currentTime = timeGetTime();
   1.988 +				DWORD timeSinceLastEvent = (currentTime - iLastTimerEventTime);
   1.989 +				
   1.990 +				// Clamp the resulting value to the duration of the timer, to prevent the millisecond count
   1.991 +				// going backwards if Windows is busy and latency becomes an issue
   1.992 +				if (timeSinceLastEvent > iSimulatedMsecDuration)
   1.993 +					timeSinceLastEvent = iSimulatedMsecDuration;
   1.994 +				
   1.995 +				TUint bytesTransferredSincePause = iBytesSincePauseReportedToLdd;
   1.996 +				WAVEHDR *buf = iWaveformBufMgr->iPendingBufList[0];
   1.997 +				if(buf)
   1.998 +					{
   1.999 +					// Add on an estimate of the progress of the current transfer
  1.1000 +					bytesTransferredSincePause += ((buf->dwBufferLength * timeSinceLastEvent) / iSimulatedMsecDuration);
  1.1001 +					}
  1.1002 +				
  1.1003 +				position = bytesTransferredSincePause;
  1.1004 + 	
  1.1005 +                StopTimer(ETrue);   // Stop the timer and cancel any buffers pending
  1.1006 +				}	
  1.1007 +			
  1.1008 +			// Signal the driver thread that we have stopped recording - returning info. on any partially filled buffer.
  1.1009 +			RecordThreadNotifyDriver(position);
  1.1010 +			break;
  1.1011 +
  1.1012 +		case EResume:
  1.1013 +			if (iNoHardware)
  1.1014 +				{
  1.1015 +				// Determine how long we were paused for and add that time to the time the timer last
  1.1016 +				// triggered.  This will allow us to continue as though we had never been paused
  1.1017 +				iLastTimerEventTime = timeGetTime();
  1.1018 +				}
  1.1019 +
  1.1020 +			break;		
  1.1021 +		} 
  1.1022 +	return(KErrNone);	
  1.1023 +	}
  1.1024 +	
  1.1025 +/**
  1.1026 +Handle a timer expiry event. This is only used when no audio hardware is present, with a timer expiry corresponding
  1.1027 +to the end of a data block transfer.
  1.1028 +This function is always executed in windows thread context.
  1.1029 +*/
  1.1030 +void DWinsSoundScRxPdd::HandleRecordTimerEvent()
  1.1031 +	{
  1.1032 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd:HandleRecordTimerEvent"));
  1.1033 +	ResetEvent(iRecordTimerEvent);	// Reset the event 
  1.1034 +	
  1.1035 +	// Remove the audio buffer just filled from the pending list and save it for the driver thread.
  1.1036 +	WAVEHDR* buf=RemoveFromPendingList(iWaveformBufMgr->iPendingBufList);
  1.1037 +	__ASSERT_ALWAYS(buf != NULL,PANIC());	
  1.1038 +	TInt waveBufId=buf->dwUser;					// Work out which waveform audio buffer is completing.
  1.1039 +	
  1.1040 +	// Check if there are more audio buffers waiting to be played
  1.1041 +	buf=iWaveformBufMgr->iPendingBufList[0];
  1.1042 +	if (buf)
  1.1043 +		{
  1.1044 +		iLastTimerEventTime = timeGetTime();
  1.1045 +		StartTimer(buf);						// Re-start the timer
  1.1046 +		}
  1.1047 +	else
  1.1048 +		iTimerActive=EFalse;	
  1.1049 +		
  1.1050 +	// Notify that another audio buffer has been filled.
  1.1051 +	StartOfInterrupt();
  1.1052 +	iCompletedRecordBufHdrMask|=(1<<waveBufId);	// Update the completion status mask
  1.1053 +	iDfc.Add();
  1.1054 +	EndOfInterrupt();
  1.1055 +	return;
  1.1056 +	}
  1.1057 +				
  1.1058 +/**
  1.1059 +Initialise the data member DWinsSoundScRxPdd::iCaps with the capabilities of this audio device.
  1.1060 +*/	
  1.1061 +void DWinsSoundScRxPdd::SetCaps()
  1.1062 +	{
  1.1063 +	__KTRACE_SND(Kern::Printf(">DWinsSoundScRxPdd::SetCaps"));
  1.1064 +	
  1.1065 +	// The data transfer direction for this unit is record.
  1.1066 +	iCaps.iDirection=ESoundDirRecord;
  1.1067 +	
  1.1068 +	// Assume this unit supports mono or stereo.
  1.1069 +	iCaps.iChannels=KSoundMonoChannel|KSoundStereoChannel;
  1.1070 +	
  1.1071 +	// Assume this unit supports all sample rates.
  1.1072 +	iCaps.iRates=(KSoundRate7350Hz|KSoundRate8000Hz|KSoundRate8820Hz|KSoundRate9600Hz|KSoundRate11025Hz|
  1.1073 +				  KSoundRate12000Hz|KSoundRate14700Hz|KSoundRate16000Hz|KSoundRate22050Hz|KSoundRate24000Hz|
  1.1074 +				  KSoundRate29400Hz|KSoundRate32000Hz|KSoundRate44100Hz|KSoundRate48000Hz);
  1.1075 +	
  1.1076 +	// Assume this unit supports 8bit and 16bit PCM encoding.
  1.1077 +	iCaps.iEncodings=(KSoundEncoding8BitPCM|KSoundEncoding16BitPCM);
  1.1078 +	
  1.1079 +	// This unit only supports interleaved data format
  1.1080 +	iCaps.iDataFormats=KSoundDataFormatInterleaved;
  1.1081 +	
  1.1082 +	// The minimum request size that the device can support. 
  1.1083 +	iCaps.iRequestMinSize=0;	// No restriction
  1.1084 +	
  1.1085 +	// The request alignment that this device requires. 
  1.1086 +	iCaps.iRequestAlignment=0;	// No restriction
  1.1087 +	
  1.1088 +	// This unit is not capable of detecting changes in hardware configuration.
  1.1089 +	iCaps.iHwConfigNotificationSupport=EFalse;
  1.1090 +	}
  1.1091 +/**
  1.1092 +Start the audio timer.
  1.1093 +The timer is only used when no audio hardware is present on the machine. This is in order to introduce a delay which is
  1.1094 +equivelent to that incurred when transferring audio data over a real audio device.
  1.1095 +@param aBuffer The audio buffer which would have been transferred had a real audio device been present. This contains
  1.1096 +	information on the number of bytes to transfer.
  1.1097 +*/	
  1.1098 +void DWinsSoundScRxPdd::StartTimer(WAVEHDR* aBuffer)
  1.1099 +	{
  1.1100 +	// First, need to calculate the duration of the timer in milliseconds.
  1.1101 +	TInt bytesToPlay=aBuffer->dwBufferLength;
  1.1102 +	iSimulatedMsecDuration = bytesToPlay*1000;
  1.1103 +	iSimulatedMsecDuration /= (RateInSamplesPerSecond(iSoundConfig.iRate) * iSoundConfig.iChannels);
  1.1104 +	if (iSoundConfig.iEncoding==ESoundEncoding16BitPCM)
  1.1105 +		iSimulatedMsecDuration /= 2;
  1.1106 +	if (iSoundConfig.iEncoding==ESoundEncoding24BitPCM)
  1.1107 +		iSimulatedMsecDuration /= 3;
  1.1108 +	if (iSimulatedMsecDuration<=0)
  1.1109 +		iSimulatedMsecDuration=1;	// Round up to 1ms or timeSetEvent() will return an error.
  1.1110 +				
  1.1111 +	MMRESULT res = timeSetEvent(iSimulatedMsecDuration, KMMTimerRes, (LPTIMECALLBACK)iRecordTimerEvent, 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
  1.1112 +	__ASSERT_ALWAYS(res != NULL,PANIC()); 	// timeSetEvent error.	
  1.1113 +	iTimerID = res;							// Save the identifier for the new timer event.
  1.1114 +	iTimerActive=ETrue;
  1.1115 +	}
  1.1116 +
  1.1117 +/**
  1.1118 +Stop the audio timer.
  1.1119 +The timer is only used when no audio hardware is present on the machine. This is in order to introduce a delay which is
  1.1120 +equivelent to that incurred when transferring audio data over a real audio device.
  1.1121 +@param aCancellAll Set to ETrue in order to discard any buffers queued on the pending buffer list. EFalse otherwise.
  1.1122 +*/	
  1.1123 +void DWinsSoundScRxPdd::StopTimer(TBool aCancelAll)
  1.1124 +	{
  1.1125 +	if (iTimerActive)
  1.1126 +		{
  1.1127 +		MMRESULT res = timeKillEvent(iTimerID);
  1.1128 +		__ASSERT_ALWAYS(res == TIMERR_NOERROR,PANIC()); // timeKillEvent error	
  1.1129 +		
  1.1130 +		if (aCancelAll)
  1.1131 +			{
  1.1132 +			WAVEHDR* b;
  1.1133 +			do
  1.1134 +				b=RemoveFromPendingList(iWaveformBufMgr->iPendingBufList);
  1.1135 +			while(b);
  1.1136 +			}
  1.1137 +		}
  1.1138 +	iTimerActive=EFalse;
  1.1139 +	}	
  1.1140 +
  1.1141 +