// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32test\multimedia\t_sound_api.cpp
// 
//

/**
 @file Shared chunk sound driver API test code.
*/

#include <e32test.h>
#include <f32file.h>
#include "t_soundutils.h"

#define CHECK(aValue) {Test(aValue);}
#define CHECK_NOERROR(aValue) { TInt v=(aValue); if(v) { Test.Printf(_L("Error value = %d\n"),v); Test(EFalse,__LINE__); }}
#define CHECK_EQUAL(aValue1,aValue2) { TInt v1=(aValue1); TInt v2=(aValue2); if(v1!=v2) { Test.Printf(_L("Error value = %d\n"),v1); Test(EFalse,__LINE__); }}

_LIT(KSndLddFileName,"ESOUNDSC.LDD");
_LIT(KSndPddFileName,"SOUNDSC.PDD");

RTest Test(_L("T_SOUND_API"));
RSoundSc TxSoundDevice;
RSoundSc RxSoundDevice;

TSoundFormatsSupportedV02Buf RecordCapsBuf;
TSoundFormatsSupportedV02Buf PlayCapsBuf;
TCurrentSoundFormatV02Buf PlayFormatBuf;
TCurrentSoundFormatV02Buf RecordFormatBuf;

LOCAL_C TInt Load()
	{
	TInt r;
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-219
	@SYMTestCaseDesc 		Installing the PDD
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	Attempt to install the PDD (using User::LoadPhysicalDevice()). 
							2)	Without un-installing it, attempt to install it a second time.
	@SYMTestExpectedResults	1)	KErrNone - PDD loads successfully. 
							2)	Should fail with KErrAlreadyExists.
	@SYMREQ					PREQ1073.4 */

	Test.Start(_L("Load sound PDD"));
	r=User::LoadPhysicalDevice(KSndPddFileName);
	if (r==KErrNotFound)
		{
		Test.End();
		return(r);
		}
	CHECK(r==KErrNone || r==KErrAlreadyExists);
	r=User::LoadPhysicalDevice(KSndPddFileName);
	CHECK(r==KErrAlreadyExists);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-220
	@SYMTestCaseDesc 		Installing the LDD
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	Attempt to install the LDD (using User::LoadLogicalDevice()). 
							2)	Without un-installing it, attempt to install it a second time.
	@SYMTestExpectedResults	1)	KErrNone - LDD loads successfully. 
							2)	Should fail with KErrAlreadyExists.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Load sound LDD"));
	r=User::LoadLogicalDevice(KSndLddFileName);
	CHECK(r==KErrNone || r==KErrAlreadyExists);
	r=User::LoadPhysicalDevice(KSndPddFileName);
	CHECK(r==KErrAlreadyExists);

	Test.End();
	return(KErrNone);
	}

LOCAL_C void TestSetAudioFormat()
	{
	TInt r;
	Test.Printf(_L("Testing setting the audio format\r\n"));
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-227
	@SYMTestCaseDesc 		Setting the audio configuration - channel configuration.
	@SYMTestPriority 		Critical
	@SYMTestActions			Read the audio capabilities of the playback channel. For each of the possible 6 channel 
							configurations, issue a request on the playback channel to set this audio configuration.
	@SYMTestExpectedResults	Either KErrNone if the playback channel supports the channel configuration, or
							KErrNotSupported if the playback channel does not support the channel configuration. 
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Try to set every possible audio channel configuration"));
	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	TInt i;
	for (i=0 ; i < 6 ; i++)
		{
		PlayFormatBuf().iChannels = (i+1);
		r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
		if (PlayCapsBuf().iChannels & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			}					
		else
			{
			CHECK(r==KErrNotSupported);		// Caps reports it is not supported
			}		
		}
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-228
	@SYMTestCaseDesc 		Setting the audio configuration - sample rate.
	@SYMTestPriority 		Critical
	@SYMTestActions			Read the audio capabilities of the playback channel. For each of the possible 14 sample 
							rates, issue a request on the playback channel to set this audio configuration.
	@SYMTestExpectedResults	Either KErrNone if the playback channel supports the sample rate, or
							KErrNotSupported if the playback channel does not support the sample rate. 
	@SYMREQ					PREQ1073.4 */
		
	Test.Next(_L("Try to set every possible sample rate"));
	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	for (i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
		{
		PlayFormatBuf().iRate = (TSoundRate)i;
		r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
		if (PlayCapsBuf().iRates & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			}					
		else
			{
			CHECK(r==KErrNotSupported);		// Caps reports it is not supported
			}		
		}	
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-229
	@SYMTestCaseDesc 		Setting the audio configuration - audio encoding.
	@SYMTestPriority 		Critical
	@SYMTestActions			Read the audio capabilities of the playback channel. For each of the possible 3 audio 
							encodings, issue a request on the playback channel to set this audio configuration.
	@SYMTestExpectedResults	Either KErrNone if the playback channel supports the audio encoding, or
							KErrNotSupported if the playback channel does not support the audio encoding. 
	@SYMREQ					PREQ1073.4 */	
		
	Test.Next(_L("Try to set every possible encoding"));
	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	for (i=0 ; i <= (TInt)ESoundEncoding24BitPCM ; i++)
		{
		PlayFormatBuf().iEncoding = (TSoundEncoding)i;
		r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
		if (PlayCapsBuf().iEncodings & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			}					
		else
			{
			CHECK(r==KErrNotSupported);		// Caps reports it is not supported
			}		
		}		
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-230
	@SYMTestCaseDesc 		Setting the audio configuration - audio data format.
	@SYMTestPriority 		Critical
	@SYMTestActions			Read the audio capabilities of the playback channel. For each of the possible 2 audio data 
							formats, issue a request on the playback channel to set this audio configuration.
	@SYMTestExpectedResults	Either KErrNone if the playback channel supports the audio data format, or
							KErrNotSupported if the playback channel does not support the audio data format. 
	@SYMREQ					PREQ1073.4 */	
	
	Test.Next(_L("Try to set every possible data format"));
	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	for (i=0 ; i <= (TInt)ESoundDataFormatNonInterleaved ; i++)
		{
		PlayFormatBuf().iDataFormat = (TSoundDataFormat)i;
		r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
		if (PlayCapsBuf().iDataFormats & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			}					
		else
			{
			CHECK(r==KErrNotSupported);		// Caps reports it is not supported
			}		
		}
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-231
	@SYMTestCaseDesc 		Setting the audio configuration - altering the configuration while transferring data.
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	Read the audio capabilities of the playback channel and apply a playback audio 
								configuration that is supported by channel. Set the play buffer configuration and 
								then start playing data from one of the buffers. While still playing, attempt to alter 
								the audio configuration of the playback channel.
							2)	Read the audio capabilities of the record channel and apply an audio record 
								configuration that is supported by channel. Set the record buffer configuration and 
								then start recording data into one of the buffers. While still recording, attempt 
								to alter the audio configuration of the record channel.
	@SYMTestExpectedResults	1)	Altering the audio configuration should fail with KErrInUse. 
							2)	Altering the audio configuration should fail with KErrInUse.
	@SYMREQ					PREQ1073.4 */
		
	Test.Next(_L("Try to alter the audio format while playing"));

	// Set the audio configuration of the playback channel ready to start playing
	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
		PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;

	PlayFormatBuf().iChannels = 2;
	
	// find first supported rate and set the the audio configuration to use it
	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
	for (i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
		{
		PlayFormatBuf().iRate = (TSoundRate)i;
		r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
		if (PlayCapsBuf().iRates & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			break;
			}					
		}	
	
	PrintConfig(PlayFormatBuf(),Test);
	r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
	CHECK_NOERROR(r);
	
	// Set the play buffer configuration.
	RChunk chunk;
	TInt bufSize=BytesPerSecond(PlayFormatBuf()); 										// Large enough to hold 1 second of data.
	bufSize=ValidBufferSize(bufSize,PlayCapsBuf().iRequestMinSize,PlayFormatBuf());		// Keep the buffer length valid for driver.
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iNumBuffers=3;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	TxSoundDevice.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
	
	// Start playing
	r=MakeSineTable(PlayFormatBuf());
	CHECK_NOERROR(r);
	r=SetToneFrequency(660,PlayFormatBuf());
	CHECK_NOERROR(r);
	TPtr8 ptr(chunk.Base()+bufferConfig.iBufferOffsetList[0],bufSize);
	WriteTone(ptr,PlayFormatBuf());
	TRequestStatus stat;
	TxSoundDevice.PlayData(stat,bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);

	// Check that altering the audio format while playing - fails
	r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
	CHECK(r==KErrInUse);

	User::WaitForRequest(stat);
	CHECK_EQUAL(stat.Int(),KErrNone);
	
	Test.Next(_L("Try to alter the audio format while recording"));
	
	// Set the audio configuration of the record channel ready to start recording
	RxSoundDevice.AudioFormat(RecordFormatBuf);	// Read back the current setting which must be valid.
	if (RecordCapsBuf().iEncodings&KSoundEncoding16BitPCM)
		RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
	RecordFormatBuf().iChannels = 2;

	// find first supported rate and set the the audio configuration to use it
	for (i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
		{
		RecordFormatBuf().iRate = (TSoundRate)i;
		r=TxSoundDevice.SetAudioFormat(RecordFormatBuf);
		if (RecordCapsBuf().iRates & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			break;
			}					
		}
	
	// Use the same shared chunk for recording
	r=RxSoundDevice.SetBufferChunkOpen(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	
	// Start recording
	TInt length;
	RxSoundDevice.RecordData(stat,length);
	
	// Check that altering the audio format while recording - fails
	r=RxSoundDevice.SetAudioFormat(RecordFormatBuf);
	CHECK(r==KErrInUse);
	
	User::WaitForRequest(stat);
	TInt retOffset=stat.Int();
	CHECK(retOffset>=0);
	CHECK(length>0);
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK_NOERROR(r);
	
	RxSoundDevice.CancelRecordData();	// Stop the driver from recording.
	chunk.Close();
	}

LOCAL_C void TestSetBufferConfig(TInt aBufferConfigFlags)
	{
	
	Test.Printf(_L("Testing setting the buffer configuration\r\n"));
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-232
	@SYMTestCaseDesc 		Setting the buffer configuration - varying the number of buffers.
	@SYMTestPriority 		Critical
	@SYMTestActions			Issue a request on the playback channel to create a shared chunk (i.e. using 
							SetBufferChunkCreate()) with a buffer configuration containing a single buffer. Attempt 
							to open the same shared chunk on the record channel (i.e. using SetBufferChunkOpen()). 
							Then close the chunk.
							Repeat this same sequence using buffer configurations containing 2 - 8 buffers.
	@SYMTestExpectedResults	In every case the attempt to create and open the shared chunk should return KErrNone. 
	@SYMREQ					PREQ1073.4 */	
	
	Test.Next(_L("Test creating/opening a chunk, varying the number of buffers "));
	TInt r;
	RChunk chunk;
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iBufferSizeInBytes=0x7FE0;			// 32K - 32 bytes
	if (PlayCapsBuf().iRequestMinSize)
		bufferConfig.iBufferSizeInBytes&=~(PlayCapsBuf().iRequestMinSize-1); 	// Assumes iRequestMinSize is same for play and record
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	
	TInt i;
	for (i=1 ; i<=8 ; i++)
		{
		bufferConfig.iFlags=aBufferConfigFlags;
		bufferConfig.iNumBuffers=i;
		
		// Create the shared chunk on the play channel
		r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
		CHECK_NOERROR(r);
		TxSoundDevice.GetBufferConfig(bufferConfigBuf);
		PrintBufferConf(bufferConfig,Test);
		
		// Open the same shared chunk on the record channel
		r=RxSoundDevice.SetBufferChunkOpen(bufferConfigBuf,chunk);
		CHECK_NOERROR(r);
	
		chunk.Close();
		}
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-233
	@SYMTestCaseDesc 		Setting the buffer configuration - varying the size of the buffers.
	@SYMTestPriority 		Critical
	@SYMTestActions			Issue a request on the playback channel to create a shared chunk (i.e. using 
							SetBufferChunkCreate()) with a buffer configuration containing multiple buffers 
							each of size 32K bytes. Attempt to open the same shared chunk on the record channel 
							(i.e. using SetBufferChunkOpen()). Then close the chunk. Repeat this same sequence 
							using buffer configurations containing buffers of size 16K, 8K and 4K bytes. 
	@SYMTestExpectedResults	In every case the attempt to create and open the shared chunk should return KErrNone. 
	@SYMREQ					PREQ1073.4 */		
		
	Test.Next(_L("Test creating/opening a chunk, varying the size of the buffers "));
	bufferConfig.iNumBuffers=4;
	
	for (i=1 ; i<=8 ; i*=2)
		{
		bufferConfig.iFlags=aBufferConfigFlags;
		bufferConfig.iBufferSizeInBytes=(0x8000/i);
		
		// Create the shared chunk on the play channel
		r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
		CHECK_NOERROR(r);
		TxSoundDevice.GetBufferConfig(bufferConfigBuf);
		PrintBufferConf(bufferConfig,Test);
		
		// Open the same shared chunk on the record channel
		r=RxSoundDevice.SetBufferChunkOpen(bufferConfigBuf,chunk);
		CHECK_NOERROR(r);
		
		chunk.Close();
		}
		
	// Try creating a shared chunk for the record channel specifying an illegal buffer size.
	if (RecordCapsBuf().iRequestMinSize)
		{
		Test.Next(_L("Test creating a chunk, with an illegal buffer size"));
		bufferConfig.iNumBuffers=1;
		bufferConfig.iBufferSizeInBytes=0x1001;		// 4K + 1byte
		bufferConfig.iFlags=aBufferConfigFlags;
		r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
		CHECK(r==KErrArgument);
		chunk.Close();		
		}	
			
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-234
	@SYMTestCaseDesc 		Setting the buffer configuration - specifying the buffer offsets.
	@SYMTestPriority 		Critical
	@SYMTestActions			Issue a request on the record channel to create a shared chunk (i.e. 
							using SetBufferChunkCreate()) with an buffer configuration containing multiple buffers 
							where the offset of each buffer is specified by the client. Perform this test repeatedly 
							with buffer offsets specified as follows:-
							1)	Valid buffer offsets
							2)	Offsets resulting on overlapping  buffers
							3)	Offsets which aren't aligned with the request alignment restrictions for the device (if it has any).
	@SYMTestExpectedResults	1)	Setting the buffer configuration should return KErrNone. 
							2)	Setting the buffer configuration should fail with KErrArgument.
							3)	Setting the buffer configuration should fail with KErrArgument.
	@SYMREQ					PREQ1073.4 */			
/*		
	// ***** Setting the buffer configuration - specifying the buffer offsets is not supported. *****
	
	Test.Next(_L("Test creating a chunk, specifying the buffer offsets"));
	TInt bufSize=0x2000;
	bufferConfig.iNumBuffers=8;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iBufferOffsetList[0]=0;
	bufferConfig.iBufferOffsetList[1]=bufSize;
	bufferConfig.iBufferOffsetList[2]=bufSize*4;
	bufferConfig.iBufferOffsetList[3]=bufSize*6;
	bufferConfig.iBufferOffsetList[4]=bufSize*7;
	bufferConfig.iBufferOffsetList[5]=bufSize*9;
	bufferConfig.iBufferOffsetList[6]=bufSize*10;
	bufferConfig.iBufferOffsetList[7]=bufSize*12;
	bufferConfig.iFlags=(aBufferConfigFlags|KScFlagBufOffsetListInUse);
	bufferConfigBuf.SetLength(sizeof(bufferConfig));	// Otherwise set shorter by previous GetBufferConfig().
	r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	RxSoundDevice.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	chunk.Close();	
	
	Test.Next(_L("Test creating a chunk, with invalid buffer offsets specified"));
	
	// Firstly with 2nd buffer overlapping the 1st
	bufSize=0x2000;
	bufferConfig.iNumBuffers=3;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iBufferOffsetList[0]=0;
	bufferConfig.iBufferOffsetList[1]=bufSize/2;
	bufferConfig.iBufferOffsetList[2]=bufSize*2;
	bufferConfig.iFlags=(aBufferConfigFlags|KScFlagBufOffsetListInUse);
	r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK(r==KErrArgument);
	chunk.Close();	
	
	// Now with offset of 3rd buffer not on a page boundary
	if (RecordCapsBuf().iRequestAlignment)
		{
		bufSize=0x2000;
		bufferConfig.iNumBuffers=3;
		bufferConfig.iBufferSizeInBytes=bufSize;
		bufferConfig.iBufferOffsetList[0]=0;
		bufferConfig.iBufferOffsetList[1]=bufSize;
		bufferConfig.iBufferOffsetList[2]=(bufSize*2)+1;
		bufferConfig.iFlags=(aBufferConfigFlags|KScFlagBufOffsetListInUse);
		r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
		CHECK(r==KErrArgument);
		chunk.Close();		
		}
*/		
	}

LOCAL_C void TestPlay()
	{
	
	Test.Printf(_L("Testing play operation\r\n"));
	
	// Close and re-open the playback channel to reset the driver.
	TxSoundDevice.Close();
	TInt r = TxSoundDevice.Open(KSoundScTxUnit0);
	CHECK_NOERROR(r);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-235
	@SYMTestCaseDesc 		Play operation - playing without having set the buffer configuration.
	@SYMTestPriority 		Critical
	@SYMTestActions			Issue a request on the playback channel to play some audio data before having set-up 
							the buffer configuration.
	@SYMTestExpectedResults	The play request should fail with KErrNotReady.
	@SYMREQ					PREQ1073.4 */			
	
	Test.Next(_L("Test playing without setting buffer config"));
	TRequestStatus stat[2];
	TxSoundDevice.PlayData(stat[0],0,0x2000);	// 8K
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrNotReady);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-236
	@SYMTestCaseDesc 		Play operation - playing without having set the audio configuration.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the buffer configuration on the playback channel and then issue a request to 
							play audio data before having set-up the audio configuration
	@SYMTestExpectedResults	The play request should complete with KErrNone - with the driver using its default 
							audio configuration for the transfer.
	@SYMREQ					PREQ1073.4 */	
	
	Test.Next(_L("Test playing without setting audio config"));
	
	// Read back the default play configuration
	TxSoundDevice.AudioFormat(PlayFormatBuf);
	TCurrentSoundFormatV02 playFormat=PlayFormatBuf();
	PrintConfig(playFormat,Test);
	
	// Set the play buffer configuration.
	RChunk chunk;
	TInt bufSize=BytesPerSecond(PlayFormatBuf()); 										// Large enough to hold 1 second of data.
	bufSize=ValidBufferSize(bufSize,PlayCapsBuf().iRequestMinSize,PlayFormatBuf());		// Keep the buffer length valid for driver.
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iNumBuffers=1;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	TxSoundDevice.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
	
	// Start playing
	r=MakeSineTable(PlayFormatBuf());
	CHECK_NOERROR(r);
	r=SetToneFrequency(660,PlayFormatBuf());
	CHECK_NOERROR(r); 
	TPtr8 ptr(chunk.Base()+bufferConfig.iBufferOffsetList[0],bufSize);
	WriteTone(ptr,PlayFormatBuf());
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_NOERROR(stat[0].Int());
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-239
	@SYMTestCaseDesc 		Play operation - with invalid arguments.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the playback channel to commence playing audio data using a buffer configuration 
							containing multiple buffers. Now issue a series of transfer requests to play data where the 
							requests contain invalid request arguments as follows:-
							1)	A request with a buffer offset before the start of the first buffer.
							2)	A request with a buffer offset between buffers.
							3)	A request with a length too large for a buffer.
							4)	A request with a buffer offset that doesn't comply with the offset restrictions of 
								the driver (i.e. TSoundFormatsSupportedV02:: iRequestAlignment).
							5)	A request with a length that doesn't comply with the length restrictions of 
								the driver (i.e. TSoundFormatsSupportedV02::iRequestMinSize).
	@SYMTestExpectedResults	1)	The play request should fail with KErrArgument.
							2)	The play request should fail with KErrArgument.
							3)	The play request should fail with KErrArgument.
							4)	The play request should fail with KErrArgument.
							5)	The play request should fail with KErrArgument
	@SYMREQ					PREQ1073.4 */	
	
	Test.Next(_L("Test playing with invalid arguments"));
	
	// With a buffer offset before the start of the buffer.
	TxSoundDevice.PlayData(stat[0],(bufferConfig.iBufferOffsetList[0]-0x100),bufSize,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrArgument);
	
	// With a buffer offset beyond the end of the buffer
	TxSoundDevice.PlayData(stat[0],(bufferConfig.iBufferOffsetList[0]+bufSize+0x100),bufSize,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrArgument);
	
	// With a length too large for the buffer
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],(bufSize+0x100),KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrArgument);
	
	// With a length that doesn't comply with the length restrictions of the driver
	if (PlayCapsBuf().iRequestMinSize)
		{
		TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],(bufSize-1),KSndFlagLastSample);
		User::WaitForRequest(stat[0]);
		CHECK_EQUAL(stat[0].Int(),KErrArgument);
		}
		
	// With an offset that doesn't comply with the offset restrictions of the driver
	if (PlayCapsBuf().iRequestAlignment)
		{
		TInt ln=bufSize/2;
		if (PlayCapsBuf().iRequestMinSize)
			ln&=~(PlayCapsBuf().iRequestMinSize-1);	// Keep the buffer length valid for the driver.
		TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0]+1,ln,KSndFlagLastSample);
		User::WaitForRequest(stat[0]);
		CHECK_EQUAL(stat[0].Int(),KErrArgument);
		}	
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-242
	@SYMTestCaseDesc 		Play operation - play underflow detection.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the audio configuration on the playback channel and then setup the buffer 
							configuration. Issue a single request to play audio data from one of the buffers 
							(without supplying the KSndFlagLastSample flag) and wait for the request to complete.
	@SYMTestExpectedResults	The driver should successfully play the audio data supplied but the request should 
							return the error value: KErrUnderflow.
	@SYMREQ					PREQ1073.4 */		
	
	Test.Next(_L("Test play underflow detection"));
	
	// Now set the audio configuration to a known state.
	if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
		PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
	if (PlayCapsBuf().iRates&KSoundRate16000Hz)
		PlayFormatBuf().iRate = ESoundRate16000Hz;
	if (PlayCapsBuf().iChannels&KSoundStereoChannel)
		PlayFormatBuf().iChannels = 2;
	PrintConfig(PlayFormatBuf(),Test);
	r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
	CHECK_NOERROR(r);
	
	// Reset the play buffer configuration to correspond to the audio configuration.
	bufSize=BytesPerSecond(PlayFormatBuf()); 											// Large enough to hold 1 second of data (64K)
	bufSize=ValidBufferSize(bufSize,PlayCapsBuf().iRequestMinSize,PlayFormatBuf());		// Keep the buffer length valid for driver.
	bufferConfig.iNumBuffers=1;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	TxSoundDevice.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
	
	// Start playing
	r=MakeSineTable(PlayFormatBuf());
	CHECK_NOERROR(r);
	r=SetToneFrequency(660,PlayFormatBuf());
	CHECK_NOERROR(r); 
	ptr.Set(chunk.Base()+bufferConfig.iBufferOffsetList[0],bufSize,bufSize);
	WriteTone(ptr,PlayFormatBuf());
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize);
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrUnderflow);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-243
	@SYMTestCaseDesc 		Play operation - playing multiple transfers from a single buffer.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the audio configuration on the playback channel and setup the buffer configuration 
							so the shared chunk contains just a single large buffer. Issue a pair of requests to play 
							audio data from the buffer (marking the last with the KSndFlagLastSample flag) and wait 
							for the requests to complete.
	@SYMTestExpectedResults	The driver should successfully play the audio data supplied and both requests should 
							complete with KErrNone.
	@SYMREQ					PREQ1073.4 */	
	
	Test.Next(_L("Test playing multiple transfers from a single buffer"));
	
	// Start playing
	TInt len=bufSize/2;
	if (PlayCapsBuf().iRequestMinSize)
		len&=~(PlayCapsBuf().iRequestMinSize-1);	// Keep the buffer length valid for the driver.
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],len);
	TxSoundDevice.PlayData(stat[1],(bufferConfig.iBufferOffsetList[0]+len),len,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_NOERROR(stat[0].Int());
	User::WaitForRequest(stat[1]);
	CHECK_NOERROR(stat[1].Int());
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-244
	@SYMTestCaseDesc 		Play operation - tracking the count of bytes transferred.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the playback channel for playing audio data. 
							1)	Reset the channel's count of bytes transferred and read back the count.
							2)	Issue a play request of known length and wait for it to complete. Now read the 
								count of bytes transferred.
							3)	Reset the channel's count of bytes transferred and read back the count.
	@SYMTestExpectedResults	1)	The count of bytes transferred should equal zero.
							2)	The count of bytes transferred should equal the length of the play request.
							3)	The count of bytes transferred should equal zero.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test tracking the number of bytes played"));
	TxSoundDevice.ResetBytesTransferred();
	TInt bytesPlayed=TxSoundDevice.BytesTransferred();
	CHECK(bytesPlayed==0);
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],len,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_NOERROR(stat[0].Int());
	bytesPlayed=TxSoundDevice.BytesTransferred();
	CHECK(bytesPlayed==len);
	TxSoundDevice.ResetBytesTransferred();
	bytesPlayed=TxSoundDevice.BytesTransferred();
	CHECK(bytesPlayed==0);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-246
	@SYMTestCaseDesc 		Play operation - testing the driver's handling of PDD play errors.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the playback channel for playing audio data. Using the CustomConfig() test mode 
							supported by the driver, induce the following errors returned from the driver PDD back 
							to the LDD:-
								1)	Induce a KErrTimedOut error at the start of the transfer and then issue a play request.
								2)	Induce a KErrTimedOut error once transfer has commenced and then issue a play request. 
								Once this completes, issue a further play request.
	@SYMTestExpectedResults	1)	The play request should fail immediately with KErrTimedOut (with no audible output being 
								heard).
							2)	The driver should output a short section of audible data before the first play request 
								fails with KErrTimedOut. However, the driver should recover from this and the second 
								play request should complete with KErrNone.
	@SYMREQ					PREQ1073.4 */
	
#ifdef _DEBUG	
	Test.Next(_L("Test the driver's handling of PDD play errors"));
	
	// First induce an error at the start of the transfer
	// Use an LDD test mode which induces KErrTimedOut at the start of the transfer.
	r=TxSoundDevice.CustomConfig(KSndCustom_ForceStartTransferError);
	CHECK_NOERROR(r);
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrTimedOut);
	
	// Now induce an error once transfer has commenced
	// Use an LDD test mode which induces KErrTimedOut once transfer has commenced.
	r=TxSoundDevice.CustomConfig(KSndCustom_ForceTransferDataError);
	CHECK_NOERROR(r);
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_EQUAL(stat[0].Int(),KErrTimedOut);
	
	// Check that the driver recovers
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);
	User::WaitForRequest(stat[0]);
	CHECK_NOERROR(stat[0].Int());
#endif	
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-247
	@SYMTestCaseDesc 		Play operation - closing the channel cancels any play requests.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the playback channel for playing audio data. Issue a play request and 
							while this is outstanding, close the playback channel.
	@SYMTestExpectedResults	The outstanding request should complete with KErrCancel.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test that closing the channel cancels a play request"));
	TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],len,KSndFlagLastSample);
	CHECK(stat[0]==KRequestPending);
	TxSoundDevice.Close();
	User::WaitForRequest(stat[0]);
	CHECK(stat[0]==KErrCancel);
	
	Test.Next(_L("Re-open the channel"));
	r = TxSoundDevice.Open(KSoundScTxUnit0);
	CHECK_NOERROR(r);
	
	chunk.Close();
	}
	
LOCAL_C void TestRecord()
	{
	
	Test.Printf(_L("Testing record operation\r\n"));
	
	// Close and re-open the record channel to reset the driver.
	RxSoundDevice.Close();
	TInt r = RxSoundDevice.Open(KSoundScRxUnit0);
	CHECK_NOERROR(r);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-251
	@SYMTestCaseDesc 		Record operation - recording without having set the buffer configuration.
	@SYMTestPriority 		Critical
	@SYMTestActions			Issue a request on the record channel to record some audio data before 
							having set-up the buffer configuration.
	@SYMTestExpectedResults	The record request should fail with KErrNotReady.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test recording without setting buffer config"));
	
	TRequestStatus stat;
	TInt length;
	RxSoundDevice.RecordData(stat,length);
	User::WaitForRequest(stat);
	TInt retOffset=stat.Int();
	CHECK_EQUAL(retOffset,KErrNotReady);
	
	// Test releasing a buffer without setting buffer config
	r=RxSoundDevice.ReleaseBuffer(0);
	CHECK(r==KErrNotReady);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-252
	@SYMTestCaseDesc 		Record operation - recording without having set the audio configuration.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the buffer configuration on the record channel. 
							1)	Issue a request to record a buffer of audio data before having set-up the audio 
								configuration.
							2)	Release the buffer.
	@SYMTestExpectedResults	1)	The record request should complete with KErrNone - with the driver using its 
								default audio configuration for the transfer.
							2)	The request to release the buffer should return KErrNone
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test recording without setting audio config"));
	
	// Read back the default record configuration
	RxSoundDevice.AudioFormat(RecordFormatBuf);
	TCurrentSoundFormatV02 recordFormat=RecordFormatBuf();
	PrintConfig(recordFormat,Test);
	
	// Set the record buffer configuration.
	RChunk chunk;
	TInt bufSize=BytesPerSecond(RecordFormatBuf()); 										// Large enough to hold 1 second of data.
	bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf());		// Keep the buffer length valid for driver.
	TTestSharedChunkBufConfig bufferConfig;
	bufferConfig.iNumBuffers=3;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
	r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	RxSoundDevice.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
	
	// Start recording
	RxSoundDevice.SetVolume(KSoundMaxVolume);
	RxSoundDevice.RecordData(stat,length);		// Start recording here
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset>=0);
	CHECK(length==bufSize);
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK_NOERROR(r);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-255
	@SYMTestCaseDesc 		Record operation - invalid attempts to release a record buffer.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the record channel to record audio data. Issue a request to record a buffer of audio data
							and then release the buffer.
							1)	Request to release the same buffer just released (without having re-claimed it with a 
								further record request).
							2)	Release a further buffer - specifying an illegal buffer offset for the buffer.
							3)	Stop the driver from recording (using CancelRecordData()). Now release a buffer while 
								recording is disabled.
	@SYMTestExpectedResults	1)	The request to release the buffer should fail with KErrNotFound.
							2)	The request to release the buffer should fail with KErrNotFound.
							3)	The request to release the buffer should fail with KErrNotFound.
	@SYMREQ					PREQ1073.4 */
	
	// Test releasing a buffer twice
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK(r==KErrNotFound);
	
	// Test releasing an invalid buffer offset
	r=RxSoundDevice.ReleaseBuffer(0);
	CHECK(r==KErrNotFound);
	
	// Third test case for PBASE-T_SOUND_API-255 is performed later in this function.
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-256
	@SYMTestCaseDesc 		Record operation - record overflow detection.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the audio configuration on the record channel and then setup the buffer configuration 
							so the shared chunk contains three record buffers.
							1)	Issue a request to record a buffer of audio data (to start the driver recording).
							2)	When the request completes, release the buffer immediately.
							3)	Wait just over 2 buffer periods (i.e. the time it takes for the driver to fill 2 record 
								buffers) and then issue a further record request.
							4)	To test that the driver recovers from the overflow situation, immediately issue a further 
								record request. 
	@SYMTestExpectedResults	1)	The record request should complete with KErrNone.
							2)	The request to release the buffer should return KErrNone.
							3)	The record request should fail with KErrOverflow.
							4)	The record request should complete with KErrNone.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test for record overflow"));

	// Now set the audio configuration to a known state.
	RxSoundDevice.CancelRecordData();	// Stop the driver from recording.

	RxSoundDevice.AudioFormat(RecordFormatBuf);	// Read back the current setting which must be valid.
	if (RecordCapsBuf().iEncodings&KSoundEncoding16BitPCM)
		RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
	if (RecordCapsBuf().iChannels&KSoundStereoChannel)
		RecordFormatBuf().iChannels = 2;

	// find first supported rate and set the the audio configuration to use it
	for (TInt i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
		{
		RecordFormatBuf().iRate = (TSoundRate)i;
		r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
		if (RecordCapsBuf().iRates & (1<<i))
			{
			CHECK_NOERROR(r);				// Caps reports it is supported
			break;
			}					
		}

	PrintConfig(RecordFormatBuf(),Test);
	
	// Reset the record buffer configuration to correspond to the audio configuration.
	bufSize=BytesPerSecond(RecordFormatBuf())/2; 	 										// Large enough to hold 0.5 seconds of data (64K)
	bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf());		// Keep the buffer length valid for driver.
	bufferConfig.iNumBuffers=3;
	bufferConfig.iBufferSizeInBytes=bufSize;
	bufferConfig.iFlags=0;	
	r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
	CHECK_NOERROR(r);
	RxSoundDevice.GetBufferConfig(bufferConfigBuf);
	PrintBufferConf(bufferConfig,Test);
	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
	
	// Test releasing a buffer before we have started recording
	r=RxSoundDevice.ReleaseBuffer(bufferConfig.iBufferOffsetList[0]);
	CHECK(r==KErrNotFound);
	
	RxSoundDevice.RecordData(stat,length);	// Start recording here
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset>=0);
	CHECK(length==bufSize);
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK_NOERROR(r);
	
	User::After(1100000); // Wait 2 buffer periods (1.1 seconds) for data overflow. 
	
	RxSoundDevice.RecordData(stat,length);
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset==KErrOverflow);
	
	Test.Next(_L("Test that the driver recovers from overflow"));
	
	RxSoundDevice.RecordData(stat,length);
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset>=0);
	CHECK(length==bufSize);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-257
	@SYMTestCaseDesc 		Record operation - when client is too slow releasing buffers.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the audio configuration on the record channel and then setup the buffer configuration 
							so the shared chunk contains three record buffers. Issue a request to record a buffer of 
							audio data (to start the driver recording). When this request completes, issue a further 
							record request without releasing the first buffer.
	@SYMTestExpectedResults	The second record request should fail with KErrInUse.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test when client is too slow releasing buffers"));
	
	RxSoundDevice.RecordData(stat,length);
	User::WaitForRequest(stat);
	TInt retOffset1=stat.Int();
	CHECK(retOffset1==KErrInUse);	
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK_NOERROR(r);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-258
	@SYMTestCaseDesc 		Record operation - tracking the count of bytes transferred.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the record channel for recording audio data. 
							1)	Reset the channel's count of bytes transferred and read back the count.
							2)	Issue a record request (to start the driver recording) and wait for it to complete. Immediately read the count of bytes transferred.
							3)	Reset the channel's count of bytes transferred and read back the count
	@SYMTestExpectedResults	1)	The count of bytes transferred should equal zero.
							2)	The count of bytes transferred should equal the size of a record buffer.
							3)	The count of bytes transferred should equal zero.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test tracking the number of bytes recorded"));
	RxSoundDevice.CancelRecordData();				// Stop the driver from recording.
	RxSoundDevice.ResetBytesTransferred();
	TInt bytesRecorded=RxSoundDevice.BytesTransferred();
	CHECK(bytesRecorded==0);
	RxSoundDevice.RecordData(stat,length);			// Re-start recording here
	User::WaitForRequest(stat);
	
	// Quickly check the number of bytes recorded
	bytesRecorded=RxSoundDevice.BytesTransferred();
	CHECK(bytesRecorded==bufSize);
	
	// Now check the request was successful and release the buffer
	retOffset=stat.Int();
	CHECK(retOffset>=0);
	CHECK(length==bufSize);
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK_NOERROR(r);
	
	RxSoundDevice.ResetBytesTransferred();
	bytesRecorded=RxSoundDevice.BytesTransferred();
	CHECK(bytesRecorded==0);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-260
	@SYMTestCaseDesc 		Record operation - testing the driver's handling of PDD record errors.
	@SYMTestPriority 		Critical
	@SYMTestActions			Setup the record channel for recording. Using the CustomConfig() test mode supported by the driver, induce 
							the following errors returned from the driver PDD back to the LDD:-
							1)	Induce a KErrTimedOut error at the start of the transfer. Then, issue a record request to 
								start the driver recording. Once this completes, stop the channel from recording. 
							2)	Induce a KErrTimedOut error once transfer has commenced. Then, issue a record request to 
								re-start the driver recording. Once this completes, issue a further record request.
	@SYMTestExpectedResults	1)	The record request should fail immediately with KErrTimedOut. 
							2)	The first record request should soon fail with KErrTimedOut. However, the driver should 
								recover from this and the subsequent record request should complete with KErrNone.
	@SYMREQ					PREQ1073.4 */
	
#ifdef _DEBUG	
	Test.Next(_L("Test the driver's handling of PDD record errors"));
	
	Test.Printf(_L("Induce an error at the start of the transfer.\r\n"));
	// Use an LDD test mode which induces KErrTimedOut at the start of the transfer.
	RxSoundDevice.CancelRecordData();				// Stop the driver from recording.
	r=RxSoundDevice.CustomConfig(KSndCustom_ForceStartTransferError);
	CHECK_NOERROR(r);
	RxSoundDevice.RecordData(stat,length);			// Re-start recording here
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset==KErrTimedOut);
	RxSoundDevice.CancelRecordData();				// Stop the driver from recording.
	
	Test.Printf(_L("Induce an error once transfer has commenced.\r\n"));
	// Use an LDD test mode which induces KErrTimedOut once transfer has commenced.
	r=RxSoundDevice.CustomConfig(KSndCustom_ForceTransferDataError);
	CHECK_NOERROR(r);
	RxSoundDevice.RecordData(stat,length);			// Re-start recording here
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset==KErrTimedOut);
	
	Test.Printf(_L("Check that the driver recovers.\r\n"));
	RxSoundDevice.RecordData(stat,length);
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	CHECK(retOffset>=0);
	CHECK(length==bufSize);
	r=RxSoundDevice.ReleaseBuffer(retOffset);
	CHECK_NOERROR(r);
	
/*	Test disabled 	
	Test.Printf(_L("Induce LDD to be slow servicing transfer completes from PDD.\r\n"));
	r=RxSoundDevice.CustomConfig(KSndCustom_ForceTransferTimeout);
	CHECK_NOERROR(r);
	RxSoundDevice.RecordData(stat,length);
	User::WaitForRequest(stat);
	retOffset=stat.Int();
	Test.Printf(_L("Driver returned %d.\r\n"),retOffset); */
#endif	
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-261
	@SYMTestCaseDesc 		Record operation - closing the channel cancels any record requests.
	@SYMTestPriority 		Critical
	@SYMTestActions			Start the record channel for recording audio data. Issue a record request and while this is 
							outstanding, close the record channel
	@SYMTestExpectedResults	The outstanding request should complete with KErrCancel.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Test that closing the channel cancels a play request"));
	RxSoundDevice.RecordData(stat,length);
	CHECK(stat==KRequestPending);
	RxSoundDevice.Close();
	User::WaitForRequest(stat);
	CHECK(stat==KErrCancel);
	
	Test.Next(_L("Re-open the channel"));
	r = RxSoundDevice.Open(KSoundScRxUnit0);
	CHECK_NOERROR(r);
	
	chunk.Close();
	}

#ifdef _DEBUG
LOCAL_C void TestChangeOfHwConfigNotifier()
	{
	
	Test.Printf(_L("Testing the change of h/w config notifier\r\n"));
	
	// If support for the notifier is not supported on this platform, use a debug custom config command to force
	// support for the notifier.
	TInt r;
	if (!PlayCapsBuf().iHwConfigNotificationSupport)
		{
		r=TxSoundDevice.CustomConfig(KSndCustom_ForceHwConfigNotifSupported);
		CHECK_NOERROR(r);
		}
		
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-264
	@SYMTestCaseDesc 		Change of h/w config. notifier - receiving notification.
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	Register for notification of a change in the hardware configuration of the device on 
								either the record or playback channel. Using the CustomConfig() test mode supported by the 
								driver, trigger the notifier - signalling that the headset is not present.
							2) 	Re-register for notification of a change in the hardware configuration on the same channel.
								Again using the CustomConfig() test mode, trigger the notifier - this time signalling that the 
								headset is present.
	@SYMTestExpectedResults	1)	The outstanding request for notification should complete with KErrNone and the status of 
								the bolean aHeadsetPresent should be false.
							2)	The outstanding request for notification should complete with KErrNone and the status of
								the bolean aHeadsetPresent should be true.
	@SYMREQ					PREQ1073.4 */	
	
	// Register for notification of a change in the hardware configuration of the device.
	TRequestStatus stat;
	TBool headsetPresent=ETrue;
	TxSoundDevice.NotifyChangeOfHwConfig(stat,headsetPresent);
	CHECK(stat==KRequestPending);
	
	Test.Next(_L("Trigger the notifier"));
	// Use another debug custom config command to trigger the notifier.
	r=TxSoundDevice.CustomConfig(KSndCustom_CompleteChangeOfHwConfig,(TAny*)0x00);	// Signal headset not present.
	CHECK_NOERROR(r);
	User::WaitForRequest(stat);
	CHECK_NOERROR(stat.Int());
	CHECK(!headsetPresent);
	
	Test.Next(_L("Trigger the notifier again"));
	TxSoundDevice.NotifyChangeOfHwConfig(stat,headsetPresent);
	CHECK(stat==KRequestPending);
	r=TxSoundDevice.CustomConfig(KSndCustom_CompleteChangeOfHwConfig,(TAny*)0x01);	// Signal headset is present.
	CHECK_NOERROR(r);
	User::WaitForRequest(stat);
	CHECK_NOERROR(stat.Int());
	CHECK(headsetPresent);
	
	Test.Next(_L("Test cancelling the notifier"));
	TxSoundDevice.NotifyChangeOfHwConfig(stat,headsetPresent);
	CHECK(stat==KRequestPending);
	TxSoundDevice.CancelNotifyChangeOfHwConfig();
	User::WaitForRequest(stat);
	CHECK(stat==KErrCancel);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-265
	@SYMTestCaseDesc 		Change of h/w config. notifier - receiving notification.
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	Register for notification of a change in the hardware configuration of the device on 
								either the record or playback channel. Using the CustomConfig() test mode supported by the 
								driver, trigger the notifier - signalling that the headset is not present.
							2) 	Re-register for notification of a change in the hardware configuration on the same channel.
								Again using the CustomConfig() test mode, trigger the notifier - this time signalling that the 
								headset is present.
	@SYMTestExpectedResults	1)	The outstanding request for notification should complete with KErrNone and the status of 
								the bolean aHeadsetPresent should be false.
							2)	The outstanding request for notification should complete with KErrNone and the status of
								the bolean aHeadsetPresent should be true.
	@SYMREQ					PREQ1073.4 */	
	
	Test.Next(_L("Test that closing the channel cancels the notifier"));
	TxSoundDevice.NotifyChangeOfHwConfig(stat,headsetPresent);
	CHECK(stat==KRequestPending);
	TxSoundDevice.Close();
	User::WaitForRequest(stat);
	CHECK(stat==KErrCancel);
	
	Test.Next(_L("Re-open the channel"));
	r = TxSoundDevice.Open(KSoundScTxUnit0);
	CHECK_NOERROR(r);
	}
#endif	
	
LOCAL_C void TestUnloadDrivers()
	{
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-221
	@SYMTestCaseDesc 		Un-installing the LDD
	@SYMTestPriority 		Critical
	@SYMTestActions 		Attempt to un-install the LDD (using User::FreeLogicalDevice()). 
	@SYMTestExpectedResults KErrNone - LDD unloads successfully 
	@SYMREQ					PREQ1073.4 */
	
	TInt r=User::FreeLogicalDevice(KDevSoundScName);
	Test.Printf(_L("Unloading %S.LDD - %d\r\n"),&KDevSoundScName,r);
	CHECK_NOERROR(r);
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-222
	@SYMTestCaseDesc 		Un-installing the PDD
	@SYMTestPriority 		Critical
	@SYMTestActions 		Attempt to un-install the PDD (using User::FreePhysicalDevice()). 
	@SYMTestExpectedResults KErrNone - PDD unloads successfully 
	@SYMREQ					PREQ1073.4 */
	
	TName pddName(KDevSoundScName);
	_LIT(KPddWildcardExtension,".*");
	pddName.Append(KPddWildcardExtension);
	TFindPhysicalDevice findPD(pddName);
	TFullName findResult;
	r=findPD.Next(findResult);
	while (r==KErrNone)
		{
		r=User::FreePhysicalDevice(findResult);
		Test.Printf(_L("Unloading %S.PDD - %d\r\n"),&findResult,r);
		CHECK_NOERROR(r);
		findPD.Find(pddName); // Reset the find handle now that we have deleted something from the container.
		r=findPD.Next(findResult);
		} 
	}

/**
Invoke the helper executable, tell it what unit to open RSoundSc for.

@param aUnit Parameter to supply to RSoundSc ie. KSoundScTxUnit0, KSoundScRxUnit0
@param aExpectedError The expected return code from RSoundSc::Open
 */
static void RunHelper(TInt aUnit, TInt aExpectedError)
	{
	TInt r;
	
	RProcess ph;
	r = ph.Create(KHelperExe, KNullDesC);
	CHECK_NOERROR(r);
	r = ph.SetParameter(KSlot, aUnit); 
	CHECK_NOERROR(r);

	TRequestStatus rsh;
	ph.Logon(rsh);
	Test(rsh == KRequestPending);
	ph.Resume();
	User::WaitForRequest(rsh);

	// process has died so check the panic category and reason match the expected values
	CHECK_EQUAL(ph.ExitType(), EExitPanic);
	Test(ph.ExitCategory()==KSoundAPICaps,__LINE__,(const TText*)__FILE__);
	CHECK_EQUAL(ph.ExitReason(), aExpectedError);

	ph.Close();
	}

/**
Delete the copy of the helper exe which was created with altered capabilities
*/
static TInt DeleteHelper()
	{
	RFs fs;
	TInt r = fs.Connect();
	CHECK_NOERROR(r);
	TFileName fileName(KSysBin);
	fileName.Append(KPathDelimiter);
	fileName+=KHelperExe;
	//delete modified version of helper exe
	r = fs.Delete(fileName);
	fs.Close();
	return r;
	}

/**
Use setcap.exe to create a copy of the helper executable, t_sound_api_helper.exe
called t_sound_api_helper_caps.exe with the supplied capabilities.

@param aCaps A bitmask of capabilities to assign to helper exe.
*/
static void SetHelperCaps(TUint32 aCaps)
	{
	TInt r;
	_LIT(KCommandLineArgsFormat, "%S %08x %S\\%S");
	TBuf<128> cmdLine;
	cmdLine.Format(KCommandLineArgsFormat, &KHelperExeBase, aCaps, &KSysBin, &KHelperExe);

	RProcess p;
	r = p.Create(_L("setcap.exe"), cmdLine);
	CHECK_NOERROR(r);

	TRequestStatus rs;
	p.Logon(rs);
	CHECK_EQUAL(rs.Int(),KRequestPending);
	p.Resume();
	User::WaitForRequest(rs);

	p.Close();
	}

/**
Test that ECapabilityMultimediaDD is required
in order to open RSoundSc for playback and that
ECapabilityUserEnvironment is needed, in addition,
to open for record.
*/
static void TestCapabilityChecks()
	{
	//convert capabilities into bitmask understood by setcap.exe
	const TUint32 KUserEnvironment = 1<<ECapabilityUserEnvironment;
	const TUint32 KMultimediaDD= 1<<ECapabilityMultimediaDD;
	
	//try to delete helper just in case it has been left hanging about from a previous run which failed
	DeleteHelper();
	SetHelperCaps(NULL);
	RunHelper(KSoundScTxUnit0,KErrPermissionDenied);
	RunHelper(KSoundScRxUnit0,KErrPermissionDenied);
	
	CHECK_NOERROR(DeleteHelper());
	SetHelperCaps(KMultimediaDD);
	RunHelper(KSoundScTxUnit0,KErrNone);
	RunHelper(KSoundScRxUnit0,KErrPermissionDenied);

	CHECK_NOERROR(DeleteHelper());
	SetHelperCaps(KUserEnvironment);
	RunHelper(KSoundScTxUnit0,KErrPermissionDenied);
	RunHelper(KSoundScRxUnit0,KErrPermissionDenied);

	CHECK_NOERROR(DeleteHelper());
	SetHelperCaps(KUserEnvironment|KMultimediaDD);
	RunHelper(KSoundScTxUnit0,KErrNone);
	RunHelper(KSoundScRxUnit0,KErrNone);

	CHECK_NOERROR(DeleteHelper());
	}

TInt E32Main()
	{
	TInt r;

	__UHEAP_MARK;

	Test.Title();

	Test.Start(_L("Load"));
	if (Load()==KErrNotFound)
		{
		Test.Printf(_L("Shared chunk sound driver not supported - test skipped\r\n"));
		Test.End();
		Test.Close();
		__UHEAP_MARKEND;
		return(KErrNone);
		}

	// The __KHEAP_MARK and __KHEAP_MARKEND macros unfortunately have to be commented out or they
	// generate false positives on the x86pc target build.  This is to do with the launching of the
	// helper executable, which results in another component allocating memory and not freeing it,
	// thus causing the macros here to trigger a kern-exec 17 that is not related to the sound driver
	// itself.  The same macros are fine on other platforms.  See DEF129273 for more information
	//__KHEAP_MARK;

	Test.Next(_L("Test Capability Checking"));
	TestCapabilityChecks();
		
	Test.Next(_L("Open playback channel"));
	r = TxSoundDevice.Open(KSoundScTxUnit0);
	CHECK_NOERROR(r);
	
	Test.Next(_L("Open record channel"));
	r = RxSoundDevice.Open(KSoundScRxUnit0);
	CHECK_NOERROR(r);
	
	Test.Next(_L("Query play formats supported"));
	TxSoundDevice.Caps(PlayCapsBuf);
	TSoundFormatsSupportedV02 playCaps=PlayCapsBuf();
	PrintCaps(playCaps,Test);

	Test.Next(_L("Query record formats supported"));
	RxSoundDevice.Caps(RecordCapsBuf);
	TSoundFormatsSupportedV02 recordCaps=RecordCapsBuf();
	PrintCaps(recordCaps,Test);
	
	TestSetAudioFormat();
	TestSetBufferConfig(0);							// Without guard pages.
	TestSetBufferConfig(KScFlagUseGuardPages);		// With guard pages.
	TestPlay();
	TestRecord();
#ifdef _DEBUG		
	TestChangeOfHwConfigNotifier();
#endif			
	// Note that API testing of pause/resume and volume setting are covered in T_SOUND2.
	
	/**	@SYMTestCaseID 		PBASE-T_SOUND_API-226
	@SYMTestCaseDesc 		Closing the channel
	@SYMTestPriority 		Critical
	@SYMTestActions			1)	With a playback channel open on the device, close the channel. 
							2)	With a record channel open on the device, close the channel. 
	@SYMTestExpectedResults	1)	No errors occur closing the channel.
							2)	No errors occur closing the channel.
	@SYMREQ					PREQ1073.4 */
	
	Test.Next(_L("Close channels"));
	RxSoundDevice.Close();
	TxSoundDevice.Close();
	
	//__KHEAP_MARKEND;

	// Now that both the channels are closed, unload the LDD and the PDDs.
	TestUnloadDrivers();

	Test.End();
	Test.Close();

	Cleanup();
	
	__UHEAP_MARKEND;

	return(KErrNone);
	}
