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