kerneltest/e32test/multimedia/t_soundwav.cpp
changeset 0 a41df078684a
child 15 4122176ea935
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\multimedia\t_soundwav.cpp
       
    15 // Record wav to a file "t_soundwav filename [rate] [channels] [seconds]" where filename does not exist.
       
    16 // Play a wav file "t_soundwav filename" where filename exists.
       
    17 // 
       
    18 //
       
    19 
       
    20 /**
       
    21  @file Shared chunk sound driver WAV file player and recorder utility.
       
    22 */
       
    23 
       
    24 #include <e32test.h>
       
    25 #include <e32def.h>
       
    26 #include <e32def_private.h>
       
    27 #include "t_soundutils.h"
       
    28 #include <f32file.h>
       
    29 
       
    30 #define CHECK(aValue) {Test(aValue);}
       
    31 #define CHECK_NOERROR(aValue) { TInt v=(aValue); if(v) { Test.Printf(_L("Error value = %d\n"),v); Test(EFalse,__LINE__); }}
       
    32 #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__); }}
       
    33 
       
    34 _LIT(KSndLddFileName,"ESOUNDSC.LDD");
       
    35 _LIT(KSndPddFileName,"SOUNDSC.PDD");
       
    36 
       
    37 RTest Test(_L("T_SOUNDWAV"));
       
    38 RSoundSc TxSoundDevice;
       
    39 RSoundSc RxSoundDevice;
       
    40 
       
    41 TSoundFormatsSupportedV02Buf RecordCapsBuf;
       
    42 TSoundFormatsSupportedV02Buf PlayCapsBuf;
       
    43 TCurrentSoundFormatV02Buf PlayFormatBuf;
       
    44 TCurrentSoundFormatV02Buf RecordFormatBuf;
       
    45 
       
    46 TBuf<256> CommandLine;
       
    47 RFs Fs;
       
    48 
       
    49 //
       
    50 // This is the WAV header structure used for playing and recording files
       
    51 //
       
    52 struct WAVEheader
       
    53 	{
       
    54 	char ckID[4];				// chunk id 'RIFF'
       
    55 	TUint32 ckSize;				// chunk size
       
    56 	char wave_ckID[4];			// wave chunk id 'WAVE'
       
    57 	char fmt_ckID[4];			// format chunk id 'fmt '
       
    58 	TUint32 fmt_ckSize;			// format chunk size
       
    59 	TUint16 formatTag;			// format tag currently pcm
       
    60 	TUint16 nChannels;			// number of channels
       
    61 	TUint32 nSamplesPerSec;		// sample rate in hz
       
    62 	TUint32 nAvgBytesPerSec;	// average bytes per second
       
    63 	TUint16 nBlockAlign;		// number of bytes per sample
       
    64 	TUint16 nBitsPerSample;		// number of bits in a sample
       
    65 	char data_ckID[4];			// data chunk id 'data'
       
    66 	TUint32 data_ckSize;		// length of data chunk
       
    67 	};
       
    68 	
       
    69 LOCAL_C TInt SamplesPerSecondToRate(TInt aRateInSamplesPerSecond,TSoundRate& aRate)
       
    70 	{
       
    71 	switch (aRateInSamplesPerSecond)
       
    72 		{
       
    73 		case 7350: 	aRate=ESoundRate7350Hz; break;
       
    74 		case 8000: 	aRate=ESoundRate8000Hz; break;
       
    75 		case 8820: 	aRate=ESoundRate8820Hz; break;
       
    76 		case 9600: 	aRate=ESoundRate9600Hz; break;
       
    77 		case 11025: aRate=ESoundRate11025Hz; break;
       
    78 		case 12000: aRate=ESoundRate12000Hz; break;
       
    79 		case 14700:	aRate=ESoundRate14700Hz; break;
       
    80 		case 16000: aRate=ESoundRate16000Hz; break;
       
    81 		case 22050: aRate=ESoundRate22050Hz; break;
       
    82 		case 24000: aRate=ESoundRate24000Hz; break;
       
    83 		case 29400: aRate=ESoundRate29400Hz; break;
       
    84 		case 32000: aRate=ESoundRate32000Hz; break;
       
    85 		case 44100: aRate=ESoundRate44100Hz; break;
       
    86 		case 48000: aRate=ESoundRate48000Hz; break;
       
    87 		default: return(KErrArgument);
       
    88 		};
       
    89 	return(KErrNone);	
       
    90 	}
       
    91 	
       
    92 LOCAL_C TInt RecordBufferSizeInBytes(TCurrentSoundFormatV02& aFormat)
       
    93 	{
       
    94 	switch (aFormat.iRate)
       
    95 		{
       
    96 		case ESoundRate7350Hz: return(8192);
       
    97 		case ESoundRate8000Hz: return(8192);
       
    98 		case ESoundRate8820Hz: return(12288);
       
    99 		case ESoundRate9600Hz: return(12288);
       
   100 		case ESoundRate11025Hz: return(12288);
       
   101 		case ESoundRate12000Hz: return(12288);
       
   102 		case ESoundRate14700Hz: return(12288);
       
   103 		case ESoundRate16000Hz: return(12288);
       
   104 		case ESoundRate22050Hz: return(16384);
       
   105 		case ESoundRate24000Hz: return(16384);
       
   106 		case ESoundRate29400Hz: return(24576);
       
   107 		case ESoundRate32000Hz: return(24576);
       
   108 		case ESoundRate44100Hz: return(32768);
       
   109 		case ESoundRate48000Hz: return(32768);
       
   110 		default: return(32768);
       
   111 		};	
       
   112 	}	
       
   113 	
       
   114 LOCAL_C TInt Load()
       
   115 	{
       
   116 	TInt r;
       
   117 
       
   118 	Test.Start(_L("Load sound PDD"));
       
   119 	r=User::LoadPhysicalDevice(KSndPddFileName);
       
   120 	if (r==KErrNotFound)
       
   121 		{
       
   122 		Test.End();
       
   123 		return(r);
       
   124 		}
       
   125 	CHECK(r==KErrNone || r==KErrAlreadyExists);
       
   126 	
       
   127 	Test.Next(_L("Load sound LDD"));
       
   128 	r=User::LoadLogicalDevice(KSndLddFileName);
       
   129 	CHECK(r==KErrNone || r==KErrAlreadyExists);
       
   130 
       
   131 	Test.End();
       
   132 	return(KErrNone);
       
   133 	}
       
   134 
       
   135 LOCAL_C TInt WavPlay()
       
   136 	{
       
   137 	RChunk chunk;
       
   138 	
       
   139 	// Parse the commandline and get a filename to use
       
   140 	TLex l(CommandLine);
       
   141 	TFileName thisfile=RProcess().FileName();
       
   142 	TPtrC token=l.NextToken();
       
   143 	if (token.MatchF(thisfile)==0)
       
   144 		token.Set(l.NextToken());
       
   145 
       
   146 	if (token.Length()==0)
       
   147 		{
       
   148 		// No args, skip to end
       
   149 		Test.Printf(_L("Invalid configuration\r\n"));
       
   150 		return(KErrArgument);
       
   151 		}
       
   152 		
       
   153 	Test.Next(_L("Play Wav file"));
       
   154 
       
   155 	// Assume that the argument is a WAV filename
       
   156 	TFileName wavFilename=token;
       
   157 	TInt r;
       
   158 	RFile source;
       
   159 	r = source.Open(Fs,wavFilename,EFileRead);
       
   160 	if (r!=KErrNone)
       
   161 		{
       
   162 		Test.Printf(_L("Open failed(%d)\r\n"), r);
       
   163 		return(r);
       
   164 		}
       
   165 
       
   166 	// Read the pcm header
       
   167 	WAVEheader header;
       
   168 	TPtr8 headerDes((TUint8 *)&header,sizeof(struct WAVEheader),sizeof(struct WAVEheader));
       
   169 	r = source.Read(headerDes);
       
   170 	if (r!=KErrNone)
       
   171 		{
       
   172 		source.Close();
       
   173 		return(r);
       
   174 		}
       
   175 	Test.Printf(_L("Header Read %d bytes\r\n"),headerDes.Size());
       
   176 
       
   177 	if (headerDes.Size() != sizeof(struct WAVEheader)) // EOF
       
   178 		{
       
   179 		Test.Printf(_L("Couldn't read a header(%d bytes)\r\n"),headerDes.Size());
       
   180 		source.Close();
       
   181 		return(KErrCorrupt);
       
   182 		}
       
   183 
       
   184 	Test.Printf(_L("Header rate:%d channels:%d tag:%d bits:%d (%d bytes/s) align %d datalen:%d fmt_ckSize:%d ckSize:%d\n"),
       
   185 			header.nSamplesPerSec, header.nChannels, header.formatTag, header.nBitsPerSample,
       
   186 			header.nAvgBytesPerSec, header.nBlockAlign, header.data_ckSize, header.fmt_ckSize, header.ckSize);
       
   187 
       
   188 	if (header.formatTag != 1) // not pcm
       
   189 		{
       
   190 		Test.Printf(_L("Format not PCM(%d)\r\n"),header.formatTag);
       
   191 		source.Close();
       
   192 		return(KErrNotSupported);
       
   193 		}
       
   194 
       
   195 	if (header.nBitsPerSample != 16) // not 16 bit
       
   196 		{
       
   197 		Test.Printf(_L("Format not 16 bit PCM(%d bits)\r\n"),header.nBitsPerSample);
       
   198 		source.Close();
       
   199 		return(KErrNotSupported);
       
   200 		}
       
   201 		
       
   202 	TSoundRate rate;	
       
   203 	if (SamplesPerSecondToRate(header.nSamplesPerSec,rate)!=KErrNone)	
       
   204 		{
       
   205 		Test.Printf(_L("Format specifies a rate not supported(%d)\r\n"),header.nSamplesPerSec);
       
   206 		source.Close();
       
   207 		return(KErrNotSupported);
       
   208 		}
       
   209 
       
   210 	TxSoundDevice.AudioFormat(PlayFormatBuf);	// Read back the current setting which must be valid.
       
   211 	PlayFormatBuf().iChannels = header.nChannels;
       
   212 	PlayFormatBuf().iRate = rate;
       
   213 	PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
       
   214 	
       
   215 	// Set the play buffer configuration.
       
   216 	TInt bufSize=BytesPerSecond(PlayFormatBuf())/8; 	// Large enough to hold 1/8th second of data.
       
   217 	bufSize&=~(header.nBlockAlign-1);					// Keep the buffer length a multiple of the bytes per sample (assumes 16bitPCM, 1 or 2 chans).
       
   218 	if (PlayCapsBuf().iRequestMinSize)
       
   219 		bufSize&=~(PlayCapsBuf().iRequestMinSize-1); 	// Keep the buffer length valid for the driver.
       
   220 	TTestSharedChunkBufConfig bufferConfig;
       
   221 	bufferConfig.iNumBuffers=3;
       
   222 	bufferConfig.iBufferSizeInBytes=bufSize;
       
   223 	bufferConfig.iFlags=0;	
       
   224 	PrintBufferConf(bufferConfig,Test);
       
   225 	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
       
   226 	r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
       
   227 	if (r!=KErrNone)
       
   228 		{
       
   229 		Test.Printf(_L("Buffer configuration not supported(%d)\r\n"),r);
       
   230 		source.Close();
       
   231 		return(r);
       
   232 		}
       
   233 	TxSoundDevice.GetBufferConfig(bufferConfigBuf);			// Read back the configuration - to get the buffer offsets
       
   234 	CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
       
   235 
       
   236 	// Set the audio play configuration.
       
   237 	TxSoundDevice.SetVolume(KSoundMaxVolume - (KSoundMaxVolume / 4)); // set volume to 75%
       
   238 	PrintConfig(PlayFormatBuf(),Test);
       
   239 	r=TxSoundDevice.SetAudioFormat(PlayFormatBuf);
       
   240 	if (r!=KErrNone)
       
   241 		{
       
   242 		Test.Printf(_L("Format not supported\r\n"));
       
   243 		source.Close();
       
   244 		chunk.Close();
       
   245 		return(r);
       
   246 		}
       
   247 	TxSoundDevice.ResetBytesTransferred();
       
   248 
       
   249 	TInt32 bytesToPlay = header.data_ckSize;
       
   250 	TTime starttime;
       
   251 	starttime.HomeTime();
       
   252 
       
   253 	TRequestStatus stat[3];
       
   254 	TPtr8* tPtr[3];
       
   255 	TInt i;
       
   256 	for (i=0;i<3;i++)
       
   257 		tPtr[i]=new TPtr8(NULL,0); 
       
   258 		
       
   259 	// Start off by issuing a play request for each buffer (assuming that the file is long enough). Use the full size
       
   260 	// of each buffer.
       
   261 	TInt stillToRead=bytesToPlay;
       
   262 	TInt stillNotPlayed=bytesToPlay;
       
   263 	TUint flags;
       
   264 	for (i=0 ; i<3 ; i++)
       
   265 		{
       
   266 		// Setup the descriptor for reading in the data from the file.
       
   267 		tPtr[i]->Set(chunk.Base()+bufferConfig.iBufferOffsetList[i],0,bufSize); 
       
   268 		
       
   269 		// If there is still data to read to play then read this into the descriptor
       
   270 		// and then write it to the driver.
       
   271 		if (stillToRead)
       
   272 			{
       
   273 			r=source.Read(*tPtr[i],Min(stillToRead,bufSize));
       
   274 			if (r!=KErrNone)
       
   275 				{
       
   276 				Test.Printf(_L("Initial file read error(%d)\r\n"),r);
       
   277 				source.Close();
       
   278 				chunk.Close();
       
   279 				return(r);
       
   280 				}
       
   281 			stillToRead-=tPtr[i]->Length();
       
   282 			flags=(stillToRead>0)?0:KSndFlagLastSample;
       
   283 			TxSoundDevice.PlayData(stat[i],bufferConfig.iBufferOffsetList[i],tPtr[i]->Length(),flags);
       
   284 			}
       
   285 		else
       
   286 			stat[i]=KRequestPending;	
       
   287 		}	
       
   288 		
       
   289 	FOREVER
       
   290 		{
       
   291 		// Wait for any one of the outstanding play requests to complete.
       
   292 		User::WaitForAnyRequest();
       
   293 	
       
   294 		// Work out which buffer this applies to
       
   295 		for (i=0 ; i<3 ; i++)
       
   296 			{
       
   297 			if (stat[i]!=KRequestPending)
       
   298 				break;
       
   299 			}
       
   300 		if (i>=3)
       
   301 			{
       
   302 			Test.Printf(_L("I/O error\r\n"));
       
   303 			source.Close();
       
   304 			chunk.Close();
       
   305 			return(KErrGeneral);
       
   306 			}
       
   307 	
       
   308 		// Check that the transfer was succesful and whether we have now played all the file.
       
   309 		if (stat[i]!=KErrNone)
       
   310 			{
       
   311 			Test.Printf(_L("Play error(%d)\r\n"),stat[i].Int());
       
   312 			source.Close();
       
   313 			chunk.Close();
       
   314 			return(stat[i].Int());
       
   315 			}
       
   316 		Test.Printf(_L("Played %d bytes(%d) - %d\r\n"),tPtr[i]->Length(),i,stat[i].Int());
       
   317 		stillNotPlayed-=tPtr[i]->Length();
       
   318 		CHECK(stillNotPlayed>=0);
       
   319 		if (!stillNotPlayed)
       
   320 			break;
       
   321 	
       
   322 		// Still more to be played so read the next part of the file into the descriptor for this
       
   323 		// buffer and then write it to the driver.
       
   324 		if (stillToRead)
       
   325 			{
       
   326 			TInt len=Min(stillToRead,bufSize);
       
   327 		
       
   328 			// If we've got to the end of the file and the driver is particular about the request length then 
       
   329 			// zero fill the entire buffer so we can play extra zeros after the last sample from the file.
       
   330 			if (len<bufSize && PlayCapsBuf().iRequestMinSize)
       
   331 				tPtr[i]->FillZ(bufSize);
       
   332 		
       
   333 			// Read the next part of the file 
       
   334 			r=source.Read(*tPtr[i],len);			// This will alter the length of the descriptor
       
   335 			if (r!=KErrNone)
       
   336 				{
       
   337 				Test.Printf(_L("File read error(%d)\r\n"),r);
       
   338 				source.Close();
       
   339 				chunk.Close();
       
   340 				return(r);
       
   341 				}
       
   342 			stillToRead-=tPtr[i]->Length();
       
   343 		
       
   344 			// If we've got to the end of the file and the driver is particular about the request length then
       
   345 			// round up the length to the next valid boundary. This is OK since we zero filled.
       
   346 			if (tPtr[i]->Length() < bufSize && PlayCapsBuf().iRequestMinSize)
       
   347 				{
       
   348 				TUint m=PlayCapsBuf().iRequestMinSize-1;
       
   349 				len=(tPtr[i]->Length() + m) & ~m;
       
   350 				}
       
   351 		
       
   352 			// Write it to the driver.
       
   353 			flags=(stillToRead>0)?0:KSndFlagLastSample;
       
   354 			TxSoundDevice.PlayData(stat[i],bufferConfig.iBufferOffsetList[i],len,flags);
       
   355 			}
       
   356 		else
       
   357 			stat[i]=KRequestPending;		
       
   358 		}
       
   359 	
       
   360 	// Delete all the variables again.	
       
   361 	for (i=0 ; i<3 ; i++)
       
   362 		delete tPtr[i];
       
   363 	
       
   364 	TTime endtime;
       
   365 	endtime.HomeTime();
       
   366 
       
   367 	Test.Printf(_L("Done playing\r\n"));
       
   368 	Test.Printf(_L("Bytes played = %d\r\n"),TxSoundDevice.BytesTransferred());
       
   369 	Test.Printf(_L("Delta time = %d\r\n"),endtime.Int64()-starttime.Int64());
       
   370 
       
   371 	chunk.Close();
       
   372 	source.Close();
       
   373 	return(KErrNone);
       
   374 	}
       
   375 
       
   376 LOCAL_C TInt WavRecord()
       
   377 	{
       
   378 	// Parse the commandline and get a filename to use
       
   379 	TLex l(CommandLine);
       
   380 	TParse destinationName;
       
   381 	if (destinationName.SetNoWild(l.NextToken(),0,0)!=KErrNone)
       
   382 		{
       
   383 		Test.Printf(_L("No arg, skipping\r\n"));
       
   384 		return(KErrArgument);
       
   385 		}
       
   386 	Test.Next(_L("Record Wav file"));
       
   387 
       
   388 	// Open the file for writing
       
   389 	TInt r;
       
   390 	RFile destination;
       
   391 	r = destination.Replace(Fs,destinationName.FullName(),EFileWrite);
       
   392 	if (r!=KErrNone)
       
   393 		{
       
   394 		Test.Printf(_L("Open file for write failed(%d)\n"), r);
       
   395 		return(r);
       
   396 		}		
       
   397 	Test.Printf(_L("File opened for write\r\n"));
       
   398 	
       
   399 	Test.Next(_L("Preparing to record"));
       
   400 	
       
   401 	// Get the rate
       
   402 	TLex cl(l.NextToken());
       
   403 	TUint32 tmpRate;
       
   404 	TSoundRate rate;
       
   405 	r = cl.Val(tmpRate,EDecimal);
       
   406 	if (r == KErrNone && (r=SamplesPerSecondToRate(tmpRate,rate))==KErrNone)
       
   407 		{
       
   408 		Test.Printf(_L("Parsed rate: %d\r\n"), tmpRate);
       
   409 		RecordFormatBuf().iRate = rate;
       
   410 		}
       
   411 	else
       
   412 		{
       
   413 		Test.Printf(_L("Parse rate failed(%d)\r\n"),r);
       
   414 		RecordFormatBuf().iRate = ESoundRate32000Hz;
       
   415 		}
       
   416 
       
   417 	// Get number of channels
       
   418 	TLex cl_chan(l.NextToken());
       
   419 	TUint32 tmpChannels;
       
   420 	r = cl_chan.Val(tmpChannels,EDecimal);
       
   421 	if (r == KErrNone)
       
   422 		{
       
   423 		Test.Printf(_L("Parsed %d channels\r\n"),tmpChannels);
       
   424 		RecordFormatBuf().iChannels = tmpChannels;
       
   425 		}
       
   426 	else
       
   427 		{
       
   428 		Test.Printf(_L("Parse channels failed(%d)\r\n"), r);
       
   429 		RecordFormatBuf().iChannels = 2;
       
   430 		}
       
   431 
       
   432 	RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
       
   433 	
       
   434 	// Set the record buffer configuration.
       
   435 	RChunk chunk;
       
   436 	TTestSharedChunkBufConfig bufferConfig;
       
   437 	bufferConfig.iNumBuffers=4;
       
   438 	bufferConfig.iBufferSizeInBytes=RecordBufferSizeInBytes(RecordFormatBuf());
       
   439 	if (RecordCapsBuf().iRequestMinSize)
       
   440 		bufferConfig.iBufferSizeInBytes&=~(RecordCapsBuf().iRequestMinSize-1); 	// Keep the buffer length valid for the driver.
       
   441 	bufferConfig.iFlags=0;	
       
   442 	PrintBufferConf(bufferConfig,Test);
       
   443 	TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
       
   444 	r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
       
   445 	if (r!=KErrNone)
       
   446 		{
       
   447 		Test.Printf(_L("Buffer configuration not supported(%d)\r\n"),r);
       
   448 		return(r);
       
   449 		}
       
   450 	
       
   451 	// Set the audio record configuration.
       
   452 	RxSoundDevice.SetVolume(KSoundMaxVolume);
       
   453 	PrintConfig(RecordFormatBuf(),Test);
       
   454 	r=RxSoundDevice.SetAudioFormat(RecordFormatBuf);
       
   455 	if (r!=KErrNone)
       
   456 		{
       
   457 		Test.Printf(_L("Format not supported\r\n"));
       
   458 		return(r);
       
   459 		}
       
   460 
       
   461 	// Get length in seconds
       
   462 	TLex cl_seconds(l.NextToken());
       
   463 	TUint32 tmpSeconds;
       
   464 	r = cl_seconds.Val(tmpSeconds,EDecimal);
       
   465 	if (r == KErrNone)
       
   466 		{
       
   467 		Test.Printf(_L("Parsed %d seconds\r\n"),tmpSeconds);
       
   468 		}
       
   469 	else
       
   470 		{
       
   471 		Test.Printf(_L("Parse seconds failed(%d)\r\n"),r);
       
   472 		tmpSeconds=10;
       
   473 		}
       
   474 	TInt bytesToRecord = BytesPerSecond(RecordFormatBuf())*tmpSeconds;	
       
   475 		
       
   476 	Test.Next(_L("Recording..."));
       
   477 	
       
   478 	// Lay down a file header
       
   479 	WAVEheader header;
       
   480 	TPtr8 headerDes((TUint8 *)&header, sizeof(struct WAVEheader), sizeof(struct WAVEheader));
       
   481 
       
   482 	// "RIFF"
       
   483 	header.ckID[0] = 'R'; header.ckID[1] = 'I';
       
   484 	header.ckID[2] = 'F'; header.ckID[3] = 'F';
       
   485 	// "WAVE"
       
   486 	header.wave_ckID[0] = 'W'; header.wave_ckID[1] = 'A';
       
   487 	header.wave_ckID[2] = 'V'; header.wave_ckID[3] = 'E';
       
   488 	// "fmt "
       
   489 	header.fmt_ckID[0] = 'f'; header.fmt_ckID[1] = 'm';
       
   490 	header.fmt_ckID[2] = 't'; header.fmt_ckID[3] = ' ';
       
   491 	// "data"
       
   492 	header.data_ckID[0] = 'd'; header.data_ckID[1] = 'a';
       
   493 	header.data_ckID[2] = 't'; header.data_ckID[3] = 'a';
       
   494 
       
   495 	header.nChannels		= (TUint16)RecordFormatBuf().iChannels;
       
   496 	header.nSamplesPerSec	= RateInSamplesPerSecond(RecordFormatBuf().iRate);
       
   497 	header.nBitsPerSample	= 16;
       
   498 	header.nBlockAlign		= TUint16((RecordFormatBuf().iChannels == 2) ? 4 : 2);
       
   499 	header.formatTag		= 1;	// type 1 is PCM
       
   500 	header.fmt_ckSize		= 16;
       
   501 	header.nAvgBytesPerSec	= BytesPerSecond(RecordFormatBuf());
       
   502 	header.data_ckSize		= bytesToRecord;
       
   503 	header.ckSize			= bytesToRecord + sizeof(struct WAVEheader) - 8;
       
   504 
       
   505 	Test.Printf(_L("Header rate:%d channels:%d tag:%d bits:%d (%d bytes/s) align %d datalen:%d fmt_ckSize:%d ckSize:%d\r\n"),
       
   506 			header.nSamplesPerSec, header.nChannels, header.formatTag, header.nBitsPerSample,
       
   507 			header.nAvgBytesPerSec, header.nBlockAlign, header.data_ckSize, header.fmt_ckSize, header.ckSize, sizeof(struct WAVEheader));
       
   508 
       
   509 	r = destination.Write(headerDes);
       
   510 
       
   511 	TRequestStatus stat;
       
   512 	TInt length;
       
   513 	TPtrC8 buf;
       
   514 	
       
   515 	// Start off by issuing a record request.
       
   516 	TTime starttime;
       
   517 	starttime.HomeTime();
       
   518 	TInt bytesRecorded = 0;
       
   519 	RxSoundDevice.RecordData(stat,length);
       
   520 
       
   521 	FOREVER
       
   522 		{
       
   523 		// Wait for the outstanding record request to complete.
       
   524 		User::WaitForAnyRequest();
       
   525 		if (stat==KRequestPending)
       
   526 			return(KErrGeneral);
       
   527 			
       
   528 		// Check whether the record request was succesful.
       
   529 		TInt retOffset=stat.Int();
       
   530 		if (retOffset<0)
       
   531 			{
       
   532 			Test.Printf(_L("Record failed(%d)\r\n"),retOffset);
       
   533 			return(retOffset);
       
   534 			}
       
   535 		
       
   536 		// Successfully recorded another buffer so write the recorded data to the record file and release the buffer.
       
   537 		buf.Set((const TUint8*)(chunk.Base()+retOffset),length);
       
   538 		r=destination.Write(buf);
       
   539 		if (r!=KErrNone)
       
   540 			{
       
   541 			Test.Printf(_L("File write failed(%d)\r\n"),r);
       
   542 			return(r);
       
   543 			}
       
   544 		r=RxSoundDevice.ReleaseBuffer(retOffset);
       
   545 		if (r!=KErrNone)
       
   546 			{
       
   547 			Test.Printf(_L("Release buffer failed(%d)\r\n"),r);
       
   548 			return(r);
       
   549 			}
       
   550 		
       
   551 		Test.Printf(_L("Recorded %d more bytes - %d\r\n"),length,retOffset);
       
   552 		
       
   553 		// Check whether we have now recorded all the data. If more to record then queue a further request
       
   554 		bytesRecorded+=length;
       
   555 		if (bytesRecorded<bytesToRecord)
       
   556 			RxSoundDevice.RecordData(stat,length);
       
   557 		else
       
   558 			break;
       
   559 		}
       
   560 	
       
   561 	RxSoundDevice.CancelRecordData();	// Stop the driver from recording.
       
   562 	
       
   563 	TTime endtime;
       
   564 	endtime.HomeTime();
       
   565 
       
   566 	TInt64 elapsedTime = endtime.Int64()-starttime.Int64();	// us
       
   567 	Test.Printf(_L("Delta time = %d\r\n"),I64LOW(elapsedTime));
       
   568 	Test.Printf(_L("Seconds in buffer: %d (%d)\r\n"), bytesRecorded / header.nAvgBytesPerSec, (bytesRecorded / header.nAvgBytesPerSec)*1000000);
       
   569 
       
   570 	if (I64LOW(elapsedTime) <= (bytesRecorded / header.nAvgBytesPerSec)*1000000)
       
   571 		{
       
   572 		Test.Printf(_L("Time travelling; record took less time than it should have done\r\n"));
       
   573 		return(KErrGeneral);
       
   574 		}
       
   575 	
       
   576 	chunk.Close();
       
   577 	destination.Close();
       
   578 
       
   579 	Test.Printf(_L("Record finished\r\n"));
       
   580 	return(KErrNone);
       
   581 	}
       
   582 	
       
   583 // Quick test block to write the output of the signal generator to a file.
       
   584 // You'll need to comment out the reference to playdata in writetone and link
       
   585 // the function into the command line processing (search on this function name).	
       
   586 /*
       
   587 LOCAL_C void TestWaveformGenerator()
       
   588 	{
       
   589 	
       
   590 	Test.Next(_L("Testing waveform generator"));
       
   591 	// Parse the commandline and get a filename to use
       
   592 	TLex l(CommandLine);
       
   593 	TParse destinationName;
       
   594 	if (destinationName.SetNoWild(l.NextToken(),0,0)!=KErrNone)
       
   595 		{
       
   596 		Test.Printf(_L("No arg, skipping\r\n"));
       
   597 		return;
       
   598 		}
       
   599 
       
   600 	// Open the file for writing
       
   601 	TInt r;
       
   602 	RFile destination;
       
   603 	r = destination.Replace(Fs,destinationName.FullName(),EFileWrite);
       
   604 	if (r!=KErrNone)
       
   605 		{
       
   606 		Test.Printf(_L("Open file for write failed(%d)\r\n"), r);
       
   607 		}
       
   608 	
       
   609 	Test.Printf(_L("File opened for write\r\n"));
       
   610 	Test.Next(_L("Preparing to record data"));
       
   611 
       
   612 	// Get the rate
       
   613 	TLex cl(l.NextToken());
       
   614 	TUint32 tmpRate;
       
   615 	TSoundRate rate;
       
   616 	r = cl.Val(tmpRate,EDecimal);
       
   617 	if (r == KErrNone && (r=SamplesPerSecondToRate(tmpRate,rate))==KErrNone)
       
   618 		{
       
   619 		Test.Printf(_L("Parsed rate: %d\r\n"), tmpRate);
       
   620 		PlayFormatBuf().iRate = rate;
       
   621 		}
       
   622 	else
       
   623 		{
       
   624 		Test.Printf(_L("Parse rate failed(%d)\r\n"),r);
       
   625 		PlayFormatBuf().iRate = ESoundRate32000Hz;
       
   626 		}
       
   627 
       
   628 	// Get number of channels
       
   629 	TLex cl_chan(l.NextToken());
       
   630 	TUint32 tmpChannels;
       
   631 	r = cl_chan.Val(tmpChannels,EDecimal);
       
   632 	if (r == KErrNone)
       
   633 		{
       
   634 		Test.Printf(_L("Parsed %d channels\r\n"),tmpChannels);
       
   635 		PlayFormatBuf().iChannels = tmpChannels;
       
   636 		}
       
   637 	else
       
   638 		{
       
   639 		Test.Printf(_L("Parse channels failed(%d)\r\n"), r);
       
   640 		PlayFormatBuf().iChannels = 2;
       
   641 		}
       
   642 
       
   643 	PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
       
   644 	PrintConfig(PlayFormatBuf(),Test);
       
   645 	
       
   646 	TInt bufferSize=BytesPerSecond(PlayFormatBuf())/8;
       
   647 	TUint8* buffer = (TUint8*)User::Alloc(bufferSize*sizeof(TUint8));
       
   648 	if (buffer==NULL)
       
   649 		{
       
   650 		Test.Printf(_L("Out of memory\r\n"));
       
   651 		return;
       
   652 		}
       
   653 	TPtr8 bufferDes(buffer,bufferSize,bufferSize);	
       
   654 
       
   655 	Test.Next(_L("Recording..."));
       
   656 	TInt i = BytesPerSecond(PlayFormatBuf())*10/bufferSize;
       
   657 	TInt bytesToRecord = i * bufferSize;
       
   658 
       
   659 	// Lay down a file header
       
   660 	WAVEheader header;
       
   661 	TPtr8 headerDes((TUint8 *)&header, sizeof(struct WAVEheader), sizeof(struct WAVEheader));
       
   662 
       
   663 	// "RIFF"
       
   664 	header.ckID[0] = 'R'; header.ckID[1] = 'I';
       
   665 	header.ckID[2] = 'F'; header.ckID[3] = 'F';
       
   666 	// "WAVE"
       
   667 	header.wave_ckID[0] = 'W'; header.wave_ckID[1] = 'A';
       
   668 	header.wave_ckID[2] = 'V'; header.wave_ckID[3] = 'E';
       
   669 	// "fmt "
       
   670 	header.fmt_ckID[0] = 'f'; header.fmt_ckID[1] = 'm';
       
   671 	header.fmt_ckID[2] = 't'; header.fmt_ckID[3] = ' ';
       
   672 	// "data"
       
   673 	header.data_ckID[0] = 'd'; header.data_ckID[1] = 'a';
       
   674 	header.data_ckID[2] = 't'; header.data_ckID[3] = 'a';
       
   675 
       
   676 	header.nChannels		= PlayFormatBuf().iChannels;
       
   677 	header.nSamplesPerSec	= RateInSamplesPerSecond(PlayFormatBuf().iRate);
       
   678 	header.nBitsPerSample	= 16;
       
   679 	header.nBlockAlign		= 4;
       
   680 	header.formatTag		= 1;
       
   681 	header.fmt_ckSize		= 16;
       
   682 	header.nAvgBytesPerSec	= BytesPerSecond(PlayFormatBuf());
       
   683 	header.data_ckSize		= bytesToRecord;
       
   684 	header.ckSize			= bytesToRecord + sizeof(struct WAVEheader) - 8;
       
   685 
       
   686 	Test.Printf(_L("Header rate:%d channels:%d tag:%d bits:%d (%d bytes/s) align %d datalen:%d fmt_ckSize:%d ckSize:%d\r\n"),
       
   687 			header.nSamplesPerSec, header.nChannels, header.formatTag, header.nBitsPerSample,
       
   688 			header.nAvgBytesPerSec, header.nBlockAlign, header.data_ckSize, header.fmt_ckSize, header.ckSize);
       
   689 
       
   690 	r = destination.Write(headerDes);
       
   691 
       
   692 	MakeSineTable(PlayFormatBuf());
       
   693 	SetToneFrequency(440,PlayFormatBuf()); // 'A'
       
   694 
       
   695 	while(--i>0)
       
   696 		{
       
   697 		WriteTone(bufferDes,PlayFormatBuf());
       
   698 		r = destination.Write(bufferDes);
       
   699 		if (r!=KErrNone)
       
   700 			{
       
   701 			Test.Printf(_L("Write failed(%d)\r\n"),r);
       
   702 			break;
       
   703 			}
       
   704 		}
       
   705 	Test.Printf(_L("Finished\r\n"));
       
   706 
       
   707 	delete buffer;
       
   708 	destination.Close();
       
   709 	}
       
   710 */
       
   711 LOCAL_C void TestUnloadDrivers()
       
   712 	{
       
   713 	TInt r=User::FreeLogicalDevice(KDevSoundScName);
       
   714 	Test.Printf(_L("Unloading %S.LDD - %d\r\n"),&KDevSoundScName,r);
       
   715 	CHECK_NOERROR(r);
       
   716 	
       
   717 	TName pddName(KDevSoundScName);
       
   718 	_LIT(KPddWildcardExtension,".*");
       
   719 	pddName.Append(KPddWildcardExtension);
       
   720 	TFindPhysicalDevice findPD(pddName);
       
   721 	TFullName findResult;
       
   722 	r=findPD.Next(findResult);
       
   723 	while (r==KErrNone)
       
   724 		{
       
   725 		r=User::FreePhysicalDevice(findResult);
       
   726 		Test.Printf(_L("Unloading %S.PDD - %d\r\n"),&findResult,r);
       
   727 		CHECK_NOERROR(r);
       
   728 		findPD.Find(pddName); // Reset the find handle now that we have deleted something from the container.
       
   729 		r=findPD.Next(findResult);
       
   730 		} 
       
   731 	}
       
   732 	
       
   733 TInt E32Main()
       
   734 	{
       
   735 	TInt r;
       
   736 
       
   737 	__UHEAP_MARK;
       
   738 
       
   739 	Test.Title();
       
   740 
       
   741 	Test.Start(_L("Load"));
       
   742 	if (Load()==KErrNotFound)
       
   743 		{
       
   744 		Test.Printf(_L("Shared chunk sound driver not supported - test skipped\r\n"));
       
   745 		Test.End();
       
   746 		Test.Close();
       
   747 		__UHEAP_MARKEND;
       
   748 		return(KErrNone);
       
   749 		}
       
   750 
       
   751 	__KHEAP_MARK;
       
   752 
       
   753 	Test.Next(_L("Open playback channel"));
       
   754 	r = TxSoundDevice.Open(KSoundScTxUnit0);
       
   755 	if (r!=KErrNone)
       
   756 		{
       
   757 		Test.Printf(_L("Open playback channel error(%d)\r\n"),r);
       
   758 		Test(0);
       
   759 		}
       
   760 	
       
   761 	Test.Next(_L("Open record channel"));
       
   762 	r = RxSoundDevice.Open(KSoundScRxUnit0);
       
   763 	if (r!=KErrNone)
       
   764 		{
       
   765 		Test.Printf(_L("Open record channel error(%d)\r\n"),r);
       
   766 		Test(0);
       
   767 		}
       
   768 	
       
   769 	Test.Next(_L("Query play formats supported"));
       
   770 	TxSoundDevice.Caps(PlayCapsBuf);
       
   771 	TSoundFormatsSupportedV02 playCaps=PlayCapsBuf();
       
   772 	PrintCaps(playCaps,Test);
       
   773 
       
   774 	Test.Next(_L("Query record formats supported"));
       
   775 	RxSoundDevice.Caps(RecordCapsBuf);
       
   776 	TSoundFormatsSupportedV02 recordCaps=RecordCapsBuf();
       
   777 	PrintCaps(recordCaps,Test);
       
   778 	
       
   779 	Test.Next(_L("Connect to the file server"));
       
   780 	r = Fs.Connect();
       
   781 	if (r!=KErrNone)
       
   782 		{
       
   783 		Test.Printf(_L("Connect to the file server error(%d)\r\n"),r);
       
   784 		Test(0);
       
   785 		}
       
   786 		
       
   787 	if (User::CommandLineLength())
       
   788 		{
       
   789 		User::CommandLine(CommandLine);
       
   790 		TLex l(CommandLine);
       
   791 		TPtrC token=l.NextToken();
       
   792 
       
   793 		TInt count=0;
       
   794 		while (token.Length()!=0)
       
   795 			{
       
   796 			++count;
       
   797 			token.Set(l.NextToken());
       
   798 			}
       
   799 		Test.Printf(_L("Command line %d parameters\r\n"),count);
       
   800 
       
   801 		if (count==1)		// If 1 parameter try playing a file
       
   802 			r=WavPlay();
       
   803 		else if (count)		// If there is more than 1 parameter, try recording
       
   804 			r=WavRecord();
       
   805 		
       
   806 		//TestWaveformGenerator();
       
   807 			
       
   808 		}
       
   809 	
       
   810 	Fs.Close();
       
   811 	
       
   812 	Test.Next(_L("Close channels"));
       
   813 	RxSoundDevice.Close();
       
   814 	TxSoundDevice.Close();
       
   815 	
       
   816 	__KHEAP_MARKEND;
       
   817 
       
   818 	// Now that both the channels are closed, unload the LDD and the PDDs.
       
   819 	TestUnloadDrivers();
       
   820 
       
   821 	Test(r==KErrNone);
       
   822 
       
   823 	Test.End();
       
   824 	Test.Close();
       
   825 
       
   826 	Cleanup();
       
   827 	
       
   828 	__UHEAP_MARKEND;
       
   829 
       
   830 	return(KErrNone);
       
   831 	}