--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/multimedia/t_sound2.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,2527 @@
+// Copyright (c) 1998-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_sound2.cpp
+//
+//
+
+/**
+ @file General test code for the shared chunk sound driver - based on T_SOUND.
+*/
+
+#include <e32test.h>
+#include "t_soundutils.h"
+#include <hal.h>
+#include <e32def.h>
+#include <e32def_private.h>
+
+// #define SOAKTEST
+
+const TSoundRate speedTable[] = {ESoundRate48000Hz,ESoundRate44100Hz,ESoundRate32000Hz,ESoundRate29400Hz,
+ ESoundRate24000Hz,ESoundRate22050Hz,ESoundRate16000Hz,ESoundRate14700Hz,
+ ESoundRate12000Hz,ESoundRate11025Hz,ESoundRate9600Hz,ESoundRate8820Hz,
+ ESoundRate8000Hz,ESoundRate7350Hz,(TSoundRate)-1}; // ALL RATES DECENDING
+
+#define CHECK(aValue) {Test(aValue,__LINE__);}
+#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__); }}
+#define CHECK_POSITIVE(aOffset) { if(aOffset<0) { Test.Printf(_L("CHECK_POSITIVE(%d) failed\n"), aOffset); Test(EFalse,__LINE__); } }
+
+_LIT(KSndLddFileName,"ESOUNDSC.LDD");
+_LIT(KSndPddFileName,"SOUNDSC.PDD");
+
+RTest Test(_L("T_SOUND2"));
+RSoundSc TxSoundDevice;
+RSoundSc RxSoundDevice;
+
+TSoundFormatsSupportedV02Buf RecordCapsBuf;
+TSoundFormatsSupportedV02Buf PlayCapsBuf;
+TCurrentSoundFormatV02Buf PlayFormatBuf;
+TCurrentSoundFormatV02Buf RecordFormatBuf;
+
+LOCAL_C TInt Load()
+ {
+ TInt r;
+
+ 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);
+
+ 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 CheckConfig(const TCurrentSoundFormatV02& aConfig,const TSoundFormatsSupportedV02& aCaps)
+ {
+ if (!((1<<(aConfig.iChannels-1)) & aCaps.iChannels))
+ CHECK_NOERROR(ETrue);
+ if (!((1<<aConfig.iRate) & aCaps.iRates))
+ CHECK_NOERROR(ETrue);
+ if (!((1<<aConfig.iEncoding) & aCaps.iEncodings))
+ CHECK_NOERROR(ETrue);
+ if (!((1<<aConfig.iDataFormat) & aCaps.iDataFormats))
+ CHECK_NOERROR(ETrue);
+ }
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Tests
+
+const TInt KMaxLinearVolume=256;
+const TInt KLinearTodB[KMaxLinearVolume+1] =
+ {
+ 0 ,158,170,177,182,186,189,192,194,196,198,200,201,203,204,205,
+ 206,207,208,209,210,211,212,213,213,214,215,215,216,217,217,218,
+ 218,219,219,220,220,221,221,222,222,223,223,224,224,224,225,225,
+ 225,226,226,226,227,227,227,228,228,228,229,229,229,230,230,230,
+ 230,231,231,231,231,232,232,232,232,233,233,233,233,234,234,234,
+ 234,235,235,235,235,235,236,236,236,236,236,237,237,237,237,237,
+ 237,238,238,238,238,238,239,239,239,239,239,239,240,240,240,240,
+ 240,240,240,241,241,241,241,241,241,241,242,242,242,242,242,242,
+ 242,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,
+ 245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,
+ 246,246,247,247,247,247,247,247,247,247,247,247,248,248,248,248,
+ 248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,
+ 250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,
+ 251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,
+ 252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,
+ 253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255
+ };
+
+LOCAL_C void TestBasicPlayFunctions()
+ {
+ TRequestStatus stat[2];
+
+ Test.Next(_L("Preparing to play..."));
+ if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+ PlayFormatBuf().iChannels = 1;
+ PrintConfig(PlayFormatBuf(),Test);
+ TInt r = TxSoundDevice.SetAudioFormat(PlayFormatBuf);
+ CHECK_NOERROR(r);
+
+ // Set the play buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(PlayFormatBuf())/8; // Large enough to hold 1/8th second of data.
+ bufSize=ValidBufferSize(bufSize,PlayCapsBuf().iRequestMinSize,PlayFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=2;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ TxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+ TPtr8* tPtr[2];
+ TInt i;
+ for (i=0;i<2;i++)
+ tPtr[i]=new TPtr8(chunk.Base()+bufferConfig.iBufferOffsetList[i],bufSize);
+
+ /** @SYMTestCaseID PBASE-T_SOUND2-249
+ @SYMTestCaseDesc Play pause / resume - pausing and resuming before playback has commenced.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the playback channel and then setup the buffer configuration.
+ 1) Attempt to resume playback before playback has been started.
+ 2) Attempt to pause playback before playback has been started.
+ @SYMTestExpectedResults 1) The resume request should complete with KErrNotReady.
+ 2) The pause request should complete with KErrNotReady
+ @SYMREQ PREQ1073.4 */
+
+ Test.Printf(_L("Resume when not playing\r\n"));
+ r=TxSoundDevice.Resume();
+ CHECK(r==KErrNotReady)
+
+ Test.Printf(_L("Pause when not playing\r\n"));
+ r=TxSoundDevice.Pause();
+ CHECK(r==KErrNotReady)
+
+ /** @SYMTestCaseID PBASE-T_SOUND2-237
+ @SYMTestCaseDesc Play operation - with zero length.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the playback channel and then setup the buffer
+ configuration. Issue a transfer request from one of the buffers to play data specifying a
+ length of zero.
+ @SYMTestExpectedResults The play request should complete with KErrNone.
+ @SYMREQ PREQ1073.4 */
+
+ Test.Next(_L("Play empty buffer"));
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],0,KSndFlagLastSample); // Play length of zero
+ User::WaitForRequest(stat[0]);
+ CHECK_EQUAL(stat[0].Int(),KErrNone);
+
+ /** @SYMTestCaseID PBASE-T_SOUND2-238
+ @SYMTestCaseDesc Play operation - with a short transfer.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the playback channel and then setup the buffer configuration.
+ 1) Issue a transfer requests from one of the buffers to play data, specifying a length equal to the
+ minimum request size that the device supports - i.e.
+ TSoundFormatsSupportedV02::iRequestMinSize, or 2 bytes, whichever is greater.
+ 2) Issue a transfer requests from one of the buffers to play data, specifying a length equal
+ to twice the minimum request size that the device supports, or 34 bytes, whichever
+ is greater.
+ @SYMTestExpectedResults 1) The play request should complete with KErrNone.
+ 2) The play request should complete with KErrNone.
+ @SYMREQ PREQ1073.4 */
+
+ Test.Next(_L("Play short buffer"));
+ TInt len=Max(2,PlayCapsBuf().iRequestMinSize);
+ Test.Printf(_L("Play length is %d bytes\r\n"),len);
+ tPtr[0]->FillZ(bufSize);
+ tPtr[1]->FillZ(len);
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,0);
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],len,KSndFlagLastSample);
+ User::WaitForRequest(stat[0]);
+ CHECK_EQUAL(stat[0].Int(),KErrNone);
+ User::WaitForRequest(stat[1]);
+ CHECK_EQUAL(stat[1].Int(),KErrNone);
+
+ Test.Next(_L("Play a slightly longer buffer"));
+ len=Max(34,(PlayCapsBuf().iRequestMinSize<<1));
+ if (PlayCapsBuf().iRequestMinSize)
+ len&=~(PlayCapsBuf().iRequestMinSize-1);
+ Test.Printf(_L("Play length is %d bytes\r\n"),len);
+ tPtr[1]->FillZ(bufSize);
+ tPtr[0]->FillZ(len);
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[1],bufSize,0); // Play 2nd buffer 1st
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[0],len,KSndFlagLastSample);
+ User::WaitForRequest(stat[0]);
+ CHECK_EQUAL(stat[0].Int(),KErrNone);
+ User::WaitForRequest(stat[1]);
+ CHECK_EQUAL(stat[1].Int(),KErrNone);
+
+ /** @SYMTestCaseID PBASE-T_SOUND2-240
+ @SYMTestCaseDesc Play operation - altering the volume.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the playback channel and then setup the buffer configuration
+ so it contains multiple buffers. Using multiple simultaneous play requests, play 4 seconds
+ of continuous tone - with each individual play request consisting of 1/8th second of tone.
+ Each time a request completes, increase the volume slightly - starting at the minimum
+ and ending at maximum volume. (Ensure the last request is marked with the
+ KSndFlagLastSample flag).
+ @SYMTestExpectedResults The driver should successfully play 4 seconds of tone with all requests completing with
+ KErrNone.
+ @SYMREQ PREQ1073.4 */
+
+ /** @SYMTestCaseID PBASE-T_SOUND2-250
+ @SYMTestCaseDesc Play pause / resume - pausing and resuming while playback is in progress.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the playback channel and then setup the buffer configuration
+ so it contains multiple buffers. Reset the channel's count of bytes transferred.
+ Using multiple simultaneous play requests, play 4 seconds of continuous tone - with
+ each individual play request consisting of 1/8th second of tone.
+ 1) After 10 requests have completed, pause transfer for 2 seconds, then resume it.
+ 2) After 20 requests have completed, attempt to resume playback while playback is not paused.
+ 3) With only 0.25 second of tone still to play, pause transfer for 1 second, then resume it.
+ 4) 10ms after resuming, pause transfer again for 1 second, then resume it.
+ 5) Once transfer has completed, read back the count of bytes transferred.
+ @SYMTestExpectedResults 1) Playback of the tone should be interrupted for 2 seconds with the pause and resume requests
+ both completing with KErrNone.
+ 2) The resume request should complete with KErrNotReady.
+ 3) Playback of the tone should be interrupted for 1 second with the pause and resume requests
+ both completing with KErrNone.
+ 4) Playback of the tone should be interrupted for 1 second with the pause and resume requests
+ both completing with KErrNone.
+ 5) The count of bytes transferred should not be affected by pausing and resuming playback
+ (i.e. it should equal the value calculated for 4 seconds at the selected sampe rate and
+ number of channels).
+ @SYMREQ PREQ1073.4 */
+
+ Test.Next(_L("Playing..."));
+ r=MakeSineTable(PlayFormatBuf());
+ CHECK_NOERROR(r);
+ r=SetToneFrequency(440,PlayFormatBuf());
+ CHECK_NOERROR(r);
+ TxSoundDevice.ResetBytesTransferred();
+ TInt remainingPlayCount = BytesPerSecond(PlayFormatBuf())*4/bufSize;
+
+ // Set the initial value for the volume.
+ TInt bytesToPlay = remainingPlayCount*bufSize;
+ TInt bytesPlayed = 0;
+ TInt vol = I64LOW(TInt64(KMaxLinearVolume)*TInt64(bytesPlayed)/TInt64(bytesToPlay));
+ vol = KLinearTodB[vol]; // Rather than varying the volume logarithmically (in dB), vary it linearly (as done by MM).
+ TxSoundDevice.SetVolume(vol);
+
+ // Issue a pair of play requests.
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize);
+ WriteTone(*tPtr[1],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],bufSize);
+
+ TInt lcount = 0;
+ TUint flags;
+ while (remainingPlayCount>2)
+ {
+ // Wait for either of the outstanding play requests to complete.
+ User::WaitForAnyRequest();
+ remainingPlayCount--;
+
+ // Work out which request this applies to.
+ for (i=0;i<2;i++)
+ {
+ if (stat[i]!=KRequestPending)
+ break;
+ }
+ CHECK(i<2);
+ CHECK_NOERROR(stat[i].Int());
+
+ // Issue a further play request using the buffer just made free.
+ WriteTone(*tPtr[i],PlayFormatBuf());
+ flags=(remainingPlayCount<=2)?KSndFlagLastSample:0;
+ TxSoundDevice.PlayData(stat[i],bufferConfig.iBufferOffsetList[i],bufSize,flags);
+
+ // Adjust the volume
+ bytesPlayed = TxSoundDevice.BytesTransferred();
+ vol = I64LOW(TInt64(KMaxLinearVolume)*TInt64(bytesPlayed)/TInt64(bytesToPlay));
+ vol = KLinearTodB[vol]; // Rather than varying the volume logarithmically (in dB), vary it linearly (as done by MM).
+ Test.Printf(_L("Bytes played = %d (vol = %d)\r\n"),bytesPlayed,vol);
+ TxSoundDevice.SetVolume(vol);
+
+ if (lcount == 10)
+ {
+ // Do a pause/resume
+ r=TxSoundDevice.Pause();
+ CHECK_NOERROR(r);
+ Test.Printf(_L("Pause 2 seconds\r\n"));
+ User::After(2000000);
+ Test.Printf(_L("Restart\r\n"));
+ r=TxSoundDevice.Resume();
+ CHECK_NOERROR(r);
+ }
+ if (lcount == 20)
+ {
+ Test.Printf(_L("Resume when playing\r\n"));
+ r=TxSoundDevice.Resume();
+ CHECK(r==KErrNotReady)
+ }
+
+ CHECK_EQUAL(TxSoundDevice.Volume(),vol);
+ CHECK_EQUAL(TxSoundDevice.SetAudioFormat(PlayFormatBuf),KErrInUse);
+ lcount++;
+ }
+
+ // Last 2 play requests still outstanding - do a pause/resume
+ r=TxSoundDevice.Pause();
+ CHECK_NOERROR(r);
+ Test.Printf(_L("Pause 1 second\r\n"));
+ User::After(1000000);
+ Test.Printf(_L("Restart\r\n"));
+ r=TxSoundDevice.Resume();
+ CHECK_NOERROR(r);
+ bytesPlayed = TxSoundDevice.BytesTransferred();
+
+ User::After(10000); // 10ms
+
+ r=TxSoundDevice.Pause();
+ Test.Printf(_L("Bytes played = %d\r\n"),bytesPlayed);
+
+ CHECK_NOERROR(r);
+ Test.Printf(_L("Pause 1 second\r\n"));
+ User::After(1000000);
+ Test.Printf(_L("Restart\r\n"));
+ r=TxSoundDevice.Resume();
+ CHECK_NOERROR(r);
+ bytesPlayed = TxSoundDevice.BytesTransferred();
+ Test.Printf(_L("Bytes played = %d\r\n"),bytesPlayed);
+
+ User::WaitForRequest(stat[0]);
+ CHECK_EQUAL(stat[0].Int(),KErrNone);
+ User::WaitForRequest(stat[1]);
+ CHECK_EQUAL(stat[1].Int(),KErrNone);
+
+ bytesPlayed = TxSoundDevice.BytesTransferred();
+ Test.Printf(_L("Bytes played = %d vs %d\n"),bytesPlayed, bytesToPlay);
+ CHECK_EQUAL(bytesToPlay,bytesPlayed);
+
+ TxSoundDevice.ResetBytesTransferred();
+ CHECK_EQUAL(TxSoundDevice.BytesTransferred(),0);
+
+ Test.Next(_L("Pause and resume when not playing"));
+ TxSoundDevice.Pause();
+ TxSoundDevice.Resume();
+
+ chunk.Close();
+ for (i=0;i<2;i++)
+ delete tPtr[i];
+ }
+
+LOCAL_C void TestBasicRecordFunctions()
+ {
+ TRequestStatus stat;
+ TInt length, r, i;
+
+ Test.Next(_L("Preparing to record..."));
+
+ 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 = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ if (RecordCapsBuf().iRates & (1<<i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+ break;
+ }
+ }
+
+ PrintConfig(RecordFormatBuf(),Test);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(RecordFormatBuf())/8; // Large enough to hold 1/8th 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; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ Test.Next(_L("Test for record overflow"));
+ RxSoundDevice.SetVolume(KSoundMaxVolume);
+ RxSoundDevice.RecordData(stat,length);
+ User::WaitForRequest(stat);
+ TInt retOffset=stat.Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length>0);
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+
+ User::After(500000); // Wait 1/2 second for data overflow.
+
+ RxSoundDevice.RecordData(stat,length);
+ User::WaitForRequest(stat);
+ retOffset=stat.Int();
+ CHECK(retOffset==KErrOverflow);
+
+ // Make sure we can issue a successful RecordData after recovering from overflow.
+ RxSoundDevice.RecordData(stat,length);
+ User::WaitForRequest(stat);
+ retOffset=stat.Int();
+ CHECK_POSITIVE(retOffset);
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ chunk.Close();
+ }
+
+/** @SYMTestCaseID PBASE-T_SOUND2-241
+ @SYMTestCaseDesc Play operation - playing all rates.
+ @SYMTestPriority Critical
+ @SYMTestActions 1) For each of the sample rates supported by the device, setup the audio configuration
+ on the playback channel for mono operation (i.e. 1 audio channel) and then setup
+ the buffer configuration so it contains multiple buffers. Using multiple simultaneous play requests,
+ play 4 seconds of continuous tone - with each individual play request consisting of 1/8th second of
+ tone. (Ensure the last request is marked with the KSndFlagLastSample flag).
+ 2) Repeat the above with the driver configured for stereo operation (i.e. 2 audio channels).
+ @SYMTestExpectedResults 1) For each of the sample rates supported by the device, the driver should successfully play
+ 4 seconds of tone, with no interruptions in the sound produced and with all requests
+ completing with KErrNone.
+ 2) For each of the sample rates supported by the device, the driver should successfully play
+ 4 seconds of tone, with no interruptions in the sound produced and with all requests
+ completing with KErrNone.
+ @SYMREQ PREQ1073.4
+*/
+LOCAL_C void TestPlayAllRates(TInt aNumChannels,TInt aNumSeconds)
+ {
+ TRequestStatus stat[2];
+ TPtr8* tPtr[2];
+ TInt i;
+ for (i=0;i<2;i++)
+ tPtr[i]=new TPtr8(NULL,0);
+
+ Test.Next(_L("Play all rates test"));
+ Test.Printf(_L("Number of channels %d, duration %d seconds\n"), aNumChannels, aNumSeconds);
+
+ if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+ PlayFormatBuf().iChannels = aNumChannels;
+ TInt r=MakeSineTable(PlayFormatBuf());
+ CHECK_NOERROR(r);
+
+ TxSoundDevice.SetVolume(KSoundMaxVolume);
+
+ RChunk chunk;
+ TInt speed = 0;
+ while (speedTable[speed]>=0)
+ {
+ PlayFormatBuf().iRate = speedTable[speed++];
+ PlayFormatBuf().iChannels = aNumChannels;
+
+ // Set the play format.
+ Test.Printf(_L("Testing playback rate %d...\r\n"),RateInSamplesPerSecond(PlayFormatBuf().iRate));
+ r = TxSoundDevice.SetAudioFormat(PlayFormatBuf);
+ if (r==KErrNotSupported)
+ {
+ Test.Printf(_L("Sample rate not supported\r\n"));
+ continue;
+ }
+ CHECK_NOERROR(r);
+
+ // Set the play buffer configuration, then read it back.
+ TInt bufSize=BytesPerSecond(PlayFormatBuf())/4; // Large enough to hold 1/4th second of data.
+ bufSize=ValidBufferSize(bufSize,PlayCapsBuf().iRequestMinSize,PlayFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=2;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ TxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+ tPtr[0]->Set(chunk.Base()+bufferConfig.iBufferOffsetList[0],0,bufSize);
+ tPtr[1]->Set(chunk.Base()+bufferConfig.iBufferOffsetList[1],0,bufSize);
+
+ r=SetToneFrequency(440,PlayFormatBuf());
+ CHECK_NOERROR(r);
+ TxSoundDevice.ResetBytesTransferred();
+ CHECK_EQUAL(TxSoundDevice.BytesTransferred(),0);
+
+ // Issue a pair of play requests.
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize);
+ WriteTone(*tPtr[1],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],bufSize);
+
+ TInt remainingPlayCount = BytesPerSecond(PlayFormatBuf())*aNumSeconds/bufSize;
+ TInt bytesToPlay = remainingPlayCount*bufSize;
+ TInt bytesPlayed = 0;
+ TInt i;
+ TUint flags;
+ while(remainingPlayCount>2)
+ {
+ // Wait for either of the outstanding play requests to complete.
+ User::WaitForAnyRequest();
+ remainingPlayCount--;
+
+ // Work out which request this applies to.
+ for (i=0;i<2;i++)
+ {
+ if (stat[i]!=KRequestPending)
+ break;
+ }
+ CHECK(i<2);
+ CHECK_NOERROR(stat[i].Int());
+
+ WriteTone(*tPtr[i],PlayFormatBuf());
+ flags=(remainingPlayCount<=2)?KSndFlagLastSample:0;
+ TxSoundDevice.PlayData(stat[i],bufferConfig.iBufferOffsetList[i],bufSize,flags);
+ }
+
+ // Last 2 play requests still outstanding.
+ User::WaitForRequest(stat[0]);
+ CHECK_NOERROR(stat[0].Int());
+ User::WaitForRequest(stat[1]);
+ CHECK_NOERROR(stat[1].Int());
+
+ Test.Printf(_L("Sample rate successful\r\n"));
+ bytesPlayed = TxSoundDevice.BytesTransferred();
+ CHECK_EQUAL(bytesToPlay,bytesPlayed);
+ chunk.Close();
+ }
+
+ for (i=0;i<2;i++)
+ delete tPtr[i];
+ }
+
+/** @SYMTestCaseID PBASE-T_SOUND2-254
+ @SYMTestCaseDesc Record operation - recording all rates.
+ @SYMTestPriority Critical
+ @SYMTestActions 1) For each of the sample rates supported by the device, setup the audio configuration on
+ the record channel for mono operation (i.e. 1 audio channel) and then setup the buffer
+ configuration so it contains multiple buffers. Using multiple simultaneous record
+ requests, record 4 seconds of audio data - with each individual record request being
+ for 1/8th second of data.
+ 2) Repeat the above with the driver configured for stereo operation (i.e. 2 audio channels).
+ @SYMTestExpectedResults 1) For each of the sample rates supported by the device, the driver should successfully
+ record 4 seconds of data, with all requests completing with KErrNone.
+ 2) For each of the sample rates supported by the device, the driver should successfully
+ record 4 seconds of data, with all requests completing with KErrNone
+ @SYMREQ PREQ1073.4
+*/
+LOCAL_C void TestRecordAllRates(TInt aNumChannels,TInt aNumSeconds)
+ {
+
+ TRequestStatus stat[2];
+ TInt length[2];
+
+ Test.Next(_L("Record all rate test"));
+ Test.Printf(_L("Number of channels %d, duration %d seconds\n"), aNumChannels, aNumSeconds);
+
+ if (RecordCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+
+ RChunk chunk;
+ TInt speed = 0;
+ while (speedTable[speed]>=0)
+ {
+ RecordFormatBuf().iRate = speedTable[speed++];
+ RecordFormatBuf().iChannels = aNumChannels;
+
+ // Set the record format.
+ Test.Printf(_L("Testing record rate %d...\r\n"),RateInSamplesPerSecond(RecordFormatBuf().iRate));
+ TInt r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ if (r==KErrNotSupported)
+ {
+ Test.Printf(_L("Sample rate not supported\r\n"));
+ continue;
+ }
+ CHECK_NOERROR(r);
+
+ // Set the record buffer configuration, then read it back.
+ TInt bufSize=BytesPerSecond(RecordFormatBuf())/8; // Large enough to hold 1/8th second of data.
+ bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=4;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ TInt remainingRecordCount = BytesPerSecond(RecordFormatBuf())*aNumSeconds/bufSize;
+ TInt bytesToRecord = remainingRecordCount*bufSize;
+ TInt bytesRecorded = 0;
+
+ // The driver rounds up the buffer size to the nearest page meaning the total duration
+ // to complete this test won't be exactly equal to 'aNumSeconds' anymore. Hence, the
+ // predicted time is no longer simply: aNumSeconds * 1000000.
+ TInt64 predictedTime = (bufSize * remainingRecordCount);
+ predictedTime*=1000000;
+ predictedTime+=BytesPerSecond(RecordFormatBuf())>>1;
+ predictedTime/=BytesPerSecond(RecordFormatBuf());
+ TTime starttime;
+ starttime.HomeTime();
+
+ // Issue a pair of record requests.
+ TInt vol = I64LOW(TInt64(KSoundMaxVolume)*TInt64(bytesRecorded)/TInt64(bytesToRecord));
+ RxSoundDevice.SetVolume(vol);
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.RecordData(stat[1],length[1]);
+ TInt currentReq=0;
+
+ TInt retOffset;
+ do
+ {
+ // Wait for the next expected request to complete.
+ User::WaitForRequest(stat[currentReq]);
+ remainingRecordCount--;
+ retOffset=stat[currentReq].Int();
+ CHECK_POSITIVE(retOffset);
+
+ CHECK(length[currentReq]>0);
+ bytesRecorded += length[currentReq];
+
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+ CHECK_EQUAL(RxSoundDevice.Volume(),vol);
+ CHECK_EQUAL(RxSoundDevice.SetAudioFormat(RecordFormatBuf),KErrInUse);
+
+ vol = I64LOW(TInt64(KSoundMaxVolume)*TInt64(bytesRecorded)/TInt64(bytesToRecord));
+ RxSoundDevice.SetVolume(vol);
+
+ // Don't issue any further record requests on the last two loop passes - to allow for the
+ // two record requests made before the loop started.
+ if (remainingRecordCount>=2)
+ RxSoundDevice.RecordData(stat[currentReq],length[currentReq]);
+
+ currentReq^=0x01; // Toggle the current req. indicator
+ }
+ while(remainingRecordCount>0);
+
+ TTime endtime;
+ endtime.HomeTime();
+ TInt64 elapsedTime = endtime.Int64()-starttime.Int64(); // us
+ Test.Printf(_L("Recorded %d bytes in %d us\n"),bytesRecorded, I64LOW(elapsedTime));
+ if (elapsedTime < predictedTime)
+ {
+ Test.Printf(_L("**** FAIL: time travelling; record took less time than it could have done\n"));
+ // CHECK_NOERROR(1);
+ }
+ CHECK_EQUAL(bytesToRecord,bytesRecorded);
+ Test.Printf(_L("Sample rate successful\r\n"));
+
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ chunk.Close();
+ }
+ }
+
+/** @SYMTestCaseID PBASE-T_SOUND2-253
+ @SYMTestCaseDesc Record operation - altering the record level.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the record channel and then setup the buffer configuration
+ so it contains multiple buffers. Using multiple simultaneous record requests, record 10
+ seconds of audio data - with each individual record request being for 1/8th second of data.
+ Each time a request completes, increase the record level slightly - starting at the minimum
+ and ending at maximum record level.
+ @SYMTestExpectedResults The driver should successfully record 10 seconds of data - i.e. all requests should complete
+ with KErrNone.
+ @SYMREQ PREQ1073.4
+*/
+LOCAL_C void TestRecordVolume(TInt aNumChannels,TInt aNumSeconds)
+ {
+ TRequestStatus stat[2];
+ TInt length[2];
+ TInt r, i;
+
+ Test.Next(_L("Preparing to test variable record levels..."));
+
+ if (RecordCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+
+ RecordFormatBuf().iChannels = aNumChannels;
+
+ // 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 = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ if (RecordCapsBuf().iRates & (1<<i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+ break;
+ }
+ }
+ PrintConfig(RecordFormatBuf(),Test);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(RecordFormatBuf())/8; // Large enough to hold 1/8th second of data.
+ bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=8;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ Test.Next(_L("Recording..."));
+ TInt remainingRecordCount = BytesPerSecond(RecordFormatBuf())*aNumSeconds/bufSize;
+ TInt bytesToRecord = remainingRecordCount*bufSize;
+ TInt bytesRecorded = 0;
+
+ // Issue a pair of record requests.
+ RxSoundDevice.SetVolume(KSoundMaxVolume);
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.RecordData(stat[1],length[1]);
+ TInt currentReq=0;
+
+ TInt retOffset;
+ do
+ {
+ // Adjust the record level.
+ TInt vol = I64LOW(TInt64(KSoundMaxVolume)*TInt64(bytesRecorded)/TInt64(bytesToRecord));
+ r=RxSoundDevice.SetVolume(vol);
+ CHECK_NOERROR(r);
+
+ // Wait for the next expected request to complete.
+ User::WaitForRequest(stat[currentReq]);
+ remainingRecordCount--;
+ retOffset=stat[currentReq].Int();
+ CHECK_POSITIVE(retOffset);
+
+ // Check the length recorded and update bytes recorded.
+ CHECK(length[currentReq]>0);
+ bytesRecorded += length[currentReq];
+ Test.Printf(_L("."));
+
+ // Read back the record level / check we can't reconfig while recording.
+ CHECK_EQUAL(RxSoundDevice.Volume(),vol);
+ CHECK_EQUAL(RxSoundDevice.SetAudioFormat(RecordFormatBuf),KErrInUse);
+
+ // Now release the buffer and issue another record request.
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+ // Don't issue any further record requests on the last two loop passes - to allow for the
+ // two record requests made before the loop started.
+ if (remainingRecordCount>=2)
+ RxSoundDevice.RecordData(stat[currentReq],length[currentReq]);
+
+ currentReq^=0x01; // Toggle the current req. indicator
+ }
+ while(remainingRecordCount>0);
+
+ CHECK_EQUAL(bytesToRecord,bytesRecorded);
+
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ Test.Printf(_L("\nBytes recorded = %d\r\n"),bytesRecorded);
+ chunk.Close();
+ }
+
+/** @SYMTestCaseID PBASE-T_SOUND2-245
+ @SYMTestCaseDesc Play operation - play cancellation.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the playback channel and then setup the buffer configuration
+ so it contains two buffers.
+ 1) Issue two simultaneous play requests, one from each buffer, each of 1/2 second of tone.
+ Wait for the first one to complete and issue a further play request from the same buffer.
+ Then immediately cancel all outstanding play requests (using CancelPlayData()).
+ 2) Issue two simultaneous play requests, one from each buffer, each of 1/2 second of tone.
+ Wait for the first one to complete and issue a further play request from the same buffer.
+ Then immediately cancel the 2nd (i.e. now active) play request (using Cancel()).
+ @SYMTestExpectedResults 1) Both outstanding requests should complete, either with KErrNone or with KErrCancel.
+ 2) The second request should complete, either with KErrNone or with KErrCancel whereas the
+ third should complete only with KErrNone.
+ @SYMREQ PREQ1073.4
+*/
+LOCAL_C void TestPlayCancel()
+ {
+ TRequestStatus stat[2];
+ TPtr8* tPtr[2];
+ TInt i, r;
+ for (i=0;i<2;i++)
+ tPtr[i]=new TPtr8(NULL,0);
+
+ Test.Next(_L("Test play cancellation"));
+
+ if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+ PlayFormatBuf().iChannels = 2;
+
+ // find first supported rate and set the the audio configuration to use it
+ for (i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
+ {
+ // check record channel
+ 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=MakeSineTable(PlayFormatBuf());
+ CHECK_NOERROR(r);
+
+ // Set the play buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(PlayFormatBuf())/2; // Large enough to hold 1/2 second of data.
+ bufSize=ValidBufferSize(bufSize,PlayCapsBuf().iRequestMinSize,PlayFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=2;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ TxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+ tPtr[0]->Set(chunk.Base()+bufferConfig.iBufferOffsetList[0],0,bufSize);
+ tPtr[1]->Set(chunk.Base()+bufferConfig.iBufferOffsetList[1],0,bufSize);
+
+ Test.Next(_L("Test cancelling all outstanding requests"));
+ // Issue a pair of play requests.
+ r=SetToneFrequency(440,PlayFormatBuf());
+ CHECK_NOERROR(r);
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize);
+ WriteTone(*tPtr[1],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],bufSize);
+
+ // Wait for the 1st request to complete. Then, re-queue a further request but then
+ // immediately cancel both requests.
+ User::WaitForRequest(stat[0]);
+ CHECK_NOERROR(stat[0].Int());
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize);
+ TxSoundDevice.CancelPlayData();
+
+ User::WaitForRequest(stat[1]);
+ if (stat[1]==KErrNone)
+ Test.Printf(_L("Note: 2nd request finished without cancel error\r\n"));
+ else
+ CHECK_EQUAL(stat[1].Int(),KErrCancel);
+ User::WaitForRequest(stat[0]);
+ if (stat[0]==KErrNone)
+ Test.Printf(_L("Note: 3rd request finished without cancel error\r\n"));
+ else
+ CHECK_EQUAL(stat[0].Int(),KErrCancel);
+
+ Test.Next(_L("Test cancelling an individual requests"));
+ // Issue a further pair of play requests.
+ r=SetToneFrequency(440,PlayFormatBuf());
+ CHECK_NOERROR(r);
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,0);
+ WriteTone(*tPtr[1],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],bufSize,0);
+
+ // Again, wait for the 1st request to complete. Then, re-queue a further request but then
+ // immediately cancel the 2nd request.
+ User::WaitForRequest(stat[0]);
+ CHECK_NOERROR(stat[0].Int());
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample);
+ TxSoundDevice.Cancel(stat[1]);
+
+ User::WaitForRequest(stat[1]);
+ if (stat[1]==KErrNone)
+ Test.Printf(_L("Note: 2nd request finished without cancel error\r\n"));
+ else
+ CHECK_EQUAL(stat[1].Int(),KErrCancel);
+ User::WaitForRequest(stat[0]);
+ CHECK_NOERROR(stat[0].Int());
+
+ chunk.Close();
+ Test.Printf(_L("Cancel play test completed successful\r\n"));
+
+ for (i=0;i<2;i++)
+ delete tPtr[i];
+ }
+
+/** @SYMTestCaseID PBASE-T_SOUND2-259
+ @SYMTestCaseDesc Record operation - record cancellation.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the record channel and then setup the buffer configuration
+ so it contains multiple buffers.
+ 1) Issue two simultaneous record requests requests, each for 1/2 second of data. Wait for
+ the first one to complete and issue a further record request. Then immediately cancel all
+ outstanding record requests (using CancelRecordData()).
+ 2) Issue two simultaneous record requests, each for 1/2 second of data. Wait for the first
+ one to complete and issue a further record request. Then immediately cancel the 2nd (i.e.
+ now active) record request (using Cancel()).
+ @SYMTestExpectedResults 1) Both outstanding requests should complete, either with KErrNone or with KErrCancel.
+ 2) The second requests should complete, either with KErrNone or with KErrCancel whereas the
+ third should complete only with KErrNone.
+ @SYMREQ PREQ1073.4
+*/
+LOCAL_C void TestRecordCancel()
+ {
+ TRequestStatus stat[2];
+ TInt length[2];
+ TPtr8* tPtr[2];
+ TInt i, r;
+ for (i=0;i<2;i++)
+ tPtr[i]=new TPtr8(NULL,0);
+
+ Test.Next(_L("Test record cancellation"));
+
+ 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 = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ if (RecordCapsBuf().iRates & (1<<i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+ break;
+ }
+ }
+
+ PrintConfig(RecordFormatBuf(),Test);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=3;
+ bufferConfig.iBufferSizeInBytes=BytesPerSecond(RecordFormatBuf())/2; // Large enough to hold 1/2 second of data.
+ bufferConfig.iBufferSizeInBytes=ValidBufferSize(bufferConfig.iBufferSizeInBytes,RecordCapsBuf().iRequestMinSize,RecordFormatBuf()); // Keep the buffer length valid for driver.
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+
+ Test.Next(_L("Test cancelling all outstanding requests"));
+ // Issue a pair of record requests.
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.RecordData(stat[1],length[1]);
+
+ // Wait for the 1st request to complete. Then, re-queue a further request but then
+ // immediately cancel both requests.
+ TInt retOffset;
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length[0]>0);
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.CancelRecordData();
+
+ User::WaitForRequest(stat[1]);
+ retOffset=stat[1].Int();
+ if (retOffset>=0)
+ Test.Printf(_L("Note: 2nd request finished without cancel error\r\n"));
+ else
+ CHECK_EQUAL(retOffset,KErrCancel);
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ if (retOffset>=0)
+ Test.Printf(_L("Note: 3rd request finished without cancel error\r\n"));
+ else
+ CHECK_EQUAL(retOffset,KErrCancel);
+
+ Test.Next(_L("Test cancelling an individual requests"));
+ // Issue a further pair of record requests.
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.RecordData(stat[1],length[1]);
+
+ // Again, wait for the 1st request to complete. Then, re-queue a further request but then
+ // immediately cancel the 2nd request.
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length[0]>0);
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.Cancel(stat[1]);
+
+ User::WaitForRequest(stat[1]);
+ retOffset=stat[1].Int();
+ if (retOffset>=0)
+ Test.Printf(_L("Note: 2nd request finished without cancel error\r\n"));
+ else
+ CHECK_EQUAL(retOffset,KErrCancel);
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length[0]>0);
+
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ chunk.Close();
+ Test.Printf(_L("Cancel record test completed successful\r\n"));
+
+ for (i=0;i<2;i++)
+ delete tPtr[i];
+ }
+
+/** @SYMTestCaseID PBASE-T_SOUND2-262
+ @SYMTestCaseDesc Play pause / resume - pausing and resuming before playback has commenced.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the record channel and then setup the buffer configuration.
+ 1) Attempt to resume recording before recording has been started.
+ 2) Attempt to pause recording before recording has been started.
+ @SYMTestExpectedResults 1) The resume request should complete with KErrNotReady.
+ 2) The pause request should complete with KErrNotReady.
+ @SYMREQ PREQ1073.4
+*/
+
+/** @SYMTestCaseID PBASE-T_SOUND2-263
+ @SYMTestCaseDesc Record pause / resume - pausing and resuming while recording is in progress.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the record channel and then setup the buffer configuration
+ so it contains multiple buffers. For the audio configuration selected, calculate the total
+ number of bytes expected to be transferred in order record 4 seconds of data. Using multiple
+ simultaneous record requests, record 4 seconds of audio data - with each individual record
+ request being for 1/8th second of data. Increment a count of actual total bytes transferred
+ by examining the count of bytes stored in the buffer for each request as it completes.
+ 1) After 10 requests have completed, pause transfer for 1 second, then resume it. If pausing
+ causes a record request to complete with a shorter than requested length then reduce the
+ count of expected total bytes transferred.
+ 2) Repeat step 1 when 20 requests have completed.
+ 3) Once transfer has completed, compare the counts of expected and actual total bytes
+ transferred.
+ @SYMTestExpectedResults 1) The pause and resume requests should both complete with KErrNone.
+ 2) The pause and resume requests should both complete with KErrNone.
+ 3) The counts should be equal.
+ @SYMREQ PREQ1073.4
+*/
+LOCAL_C void TestRecordPauseResume(TUint aChannels)
+ {
+ TRequestStatus stat[2];
+ TInt length[2];
+
+ Test.Next(_L("Test record pause and resume"));
+ RecordFormatBuf().iRate = ESoundRate44100Hz;
+ if (RecordCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+ RecordFormatBuf().iChannels = aChannels;
+ PrintConfig(RecordFormatBuf(),Test);
+ TInt r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ CHECK_NOERROR(r);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(RecordFormatBuf())/8; // Large enough to hold 1/8th second of data.
+ bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=8;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ Test.Printf(_L("Resume when not recording\r\n"));
+ r=RxSoundDevice.Resume();
+ CHECK(r==KErrNotReady)
+
+ Test.Printf(_L("Pause when not recording\r\n"));
+ r=RxSoundDevice.Pause();
+ CHECK(r==KErrNotReady)
+
+ // Record for 4 seconds
+ Test.Printf(_L("Record...\r\n"));
+ TInt remainingRecordCount = BytesPerSecond(RecordFormatBuf())*4/bufSize;
+ TInt bytesToRecord = remainingRecordCount*bufSize;
+ TInt bytesRecorded = 0;
+
+ // Issue a pair of record requests.
+ RxSoundDevice.SetVolume(KSoundMaxVolume);
+ length[0] = -42;
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ length[1] = -42;
+ RxSoundDevice.RecordData(stat[1],length[1]);
+ TInt currentReq=0;
+
+ TInt lcount = 0;
+ TInt retOffset;
+ do
+ {
+ // Do a pause / resume on 10th and 20th loop passes.
+ if (lcount && !(lcount%10))
+ {
+ // Do a pause/resume
+ Test.Printf(_L("Pause 1 second\r\n"));
+ r=RxSoundDevice.Pause();
+ CHECK_NOERROR(r);
+
+ // Pausing record may result in the driver completing with a buffer not completely full. This isn't an error. Otherwise, all outstanding
+ // requests should complete with KErrCancel. Wait for the 1st outstanding request to complete.
+ User::WaitForRequest(stat[currentReq]);
+ retOffset=stat[currentReq].Int();
+ if (retOffset>=0)
+ {
+ // Partially filled buffer. We need to adjust the bytes expected when an incomplete buffer arrives.
+ remainingRecordCount--;
+
+ CHECK_POSITIVE(length[currentReq]);
+ CHECK(length[currentReq]<=bufSize);
+ bytesRecorded += length[currentReq];
+ if (length[currentReq]<bufSize)
+ bytesToRecord-=(bufSize-length[currentReq]);
+ Test.Printf(_L("1st outstanding req partially completed(len=%d)\r\n"),length[currentReq]);
+
+ r=RxSoundDevice.ReleaseBuffer(retOffset); // Release the buffer ready for resuming
+ CHECK_NOERROR(r);
+ }
+ else
+ {
+ CHECK(retOffset==KErrCancel);
+ Test.Printf(_L("1st outstanding req cancelled\r\n"));
+ }
+ currentReq^=0x01; // Toggle the current req. indicator
+
+ // Wait for the 2nd outstanding request to complete
+ User::WaitForRequest(stat[currentReq]);
+ retOffset=stat[currentReq].Int();
+ CHECK(retOffset==KErrCancel);
+ Test.Printf(_L("2nd outstanding req cancelled\r\n"));
+
+ // Idle for 1 second, resume and then re-issue a pair of record requests.
+ User::After(1000000);
+ Test.Printf(_L("Resume\r\n"));
+ r=RxSoundDevice.Resume();
+ CHECK_NOERROR(r);
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ RxSoundDevice.RecordData(stat[1],length[1]);
+ currentReq=0;
+ }
+
+ // Wait for the next expected request to complete.
+ User::WaitForRequest(stat[currentReq]);
+ remainingRecordCount--;
+ retOffset=stat[currentReq].Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length[currentReq]>0);
+ bytesRecorded += length[currentReq];
+
+ // Now release the buffer and issue another record request
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+ // Don't issue any further record requests on the last two loop passes - to allow for the
+ // two record requests made before the loop started.
+ if (remainingRecordCount>=2)
+ RxSoundDevice.RecordData(stat[currentReq],length[currentReq]);
+ lcount++;
+ currentReq^=0x01; // Toggle the current req. indicator
+ }
+ while(remainingRecordCount>0);
+
+ CHECK_EQUAL(bytesToRecord,bytesRecorded);
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ Test.Printf(_L("Record pause/resume successful\r\n"));
+
+ Test.Next(_L("Test record pause alone"));
+
+ // Issue a single record request, wait for it to complete and then release it.
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length[0]==bufSize);
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+
+ // Without issuing another record request, wait for a duration equal to one record buffer, then pause.
+ User::After(150000); // Wait a bit longer than 1 buffer's worth (125000 is 1/8 second).
+ Test.Printf(_L("Pause\r\n"));
+ r=RxSoundDevice.Pause();
+ CHECK_NOERROR(r);
+
+ // Check that there is at least 1 buffer's worth of record data available
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ CHECK_POSITIVE(retOffset);
+ CHECK(length[0]==bufSize);
+ Test.Printf(_L("1st req completed successfully\r\n"));
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+
+ // There's probably also a partially filled buffer
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ if (retOffset>=0)
+ {
+ // Partially filled buffer.
+ CHECK(length[0]>0);
+ CHECK(length[0] <= bufSize);
+ Test.Printf(_L("2nd req partially completed(len=%d)\r\n"),length[0]);
+ r=RxSoundDevice.ReleaseBuffer(retOffset);
+ CHECK_NOERROR(r);
+ }
+ else
+ {
+ CHECK(retOffset==KErrCancel);
+ Test.Printf(_L("2nd req cancelled\r\n"));
+ }
+
+ for(;;)
+ {
+ // Read all buffers until driver is empty. The RecordData call after that should immediately return with KErrCancel
+ Test.Printf(_L("Draining driver\r\n"));
+ RxSoundDevice.RecordData(stat[0],length[0]);
+ User::WaitForRequest(stat[0]);
+ retOffset=stat[0].Int();
+ if(retOffset==KErrCancel)
+ {
+ break;
+ }
+ CHECK_NOERROR(retOffset);
+ }
+ Test.Printf(_L("Driver empty\r\n"));
+
+ r=RxSoundDevice.Resume(); // Don't leave it in paused state.
+ CHECK_NOERROR(r);
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ Test.Printf(_L("Record pause successful\r\n"));
+
+ chunk.Close();
+ }
+
+template <class T>
+class RQueue
+ {
+public:
+ RQueue()
+ : iArray()
+ { }
+ void Close()
+ {
+ iArray.Close();
+ }
+ TInt Count() const
+ {
+ return iArray.Count();
+ }
+ void PushL(const T &aItem)
+ {
+ iArray.AppendL(aItem);
+ }
+ T PopL()
+ {
+ if(iArray.Count() == 0)
+ {
+ User::Leave(KErrUnderflow);
+ }
+ const T ret = iArray[0];
+ iArray.Remove(0);
+ return ret;
+ }
+private:
+ RArray<T> iArray;
+ };
+/** @SYMTestCaseID PBASE-T_SOUND2-248
+ @SYMTestCaseDesc Play operation - simultaneous play and record on the same device, using a common shared chunk.
+ @SYMTestPriority Critical
+ @SYMTestActions Setup the audio configuration on the record channel and setup an identical audio
+ configuration on the playback channel. On the record channel, create a shared chunk
+ (i.e. using SetBufferChunkCreate()) with a buffer configuration containing multiple buffers.
+ Open the same shared chunk on the playback channel (i.e. using SetBufferChunkOpen()).
+ Set the volume to maximum level in both channels. Record 10 seconds of audio data - with
+ each individual record request being for 1/8th second of data. As soon as each record request
+ completes, issue a corresponding request on the playback channel to playback the
+ 1/8th second of data recorded. Only release each buffer for further recording once its
+ contents have been played back. Continue until 10 seconds of audio data has been both
+ recorded and played back. (Ensure the last play request is marked with the
+ KSndFlagLastSample flag).
+ @SYMTestExpectedResults The driver should successfully record and play 10 seconds of data - with all requests
+ completing with KErrNone.
+ @SYMREQ PREQ1073.4
+*/
+void TestSimultaneousPlayRecord()
+ {
+ Test.Next(_L("Preparing to record/play simultaneously..."));
+ TInt r = KErrNone;
+ TInt i;
+ // Setup the same sound configuration for both - record and play channels
+ if (RecordCapsBuf().iEncodings & KSoundEncoding16BitPCM)
+ RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+
+ if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+
+ RecordFormatBuf().iChannels = 2;
+ PlayFormatBuf().iChannels = 2;
+
+ // find first supported rate and set the the audio configuration to use it
+ for (i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
+ {
+ // check record channel
+ RecordFormatBuf().iRate = (TSoundRate)i;
+ r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ if (RecordCapsBuf().iRates & (1 << i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+
+ // ..and try the same bitrate for playback
+ PlayFormatBuf().iRate = (TSoundRate)i;
+ r = TxSoundDevice.SetAudioFormat(PlayFormatBuf);
+ if (PlayCapsBuf().iRates & (1 << i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+ break;
+ }
+ }
+ }
+
+ // both channels are set at this point, continue
+ PrintConfig(RecordFormatBuf(),Test);
+ PrintConfig(PlayFormatBuf(),Test);
+
+ // Set the volume level in both channels
+ RxSoundDevice.SetVolume(KSoundMaxVolume);
+ TxSoundDevice.SetVolume(KSoundMaxVolume - 10);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(RecordFormatBuf())/8; // Large enough to hold 1/8th second of data.
+ bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=7+7; // Must be able to use less than this
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ // Assign the same chunk to the play channel.
+ r=TxSoundDevice.SetBufferChunkOpen(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+
+ Test.Next(_L("Starting transfer..."));
+ TInt remainingRecordCount = BytesPerSecond(RecordFormatBuf())*10/bufSize; // 10 seconds
+ TInt remainingPlayCount = remainingRecordCount;
+ TInt bytesToTransfer = remainingRecordCount*bufSize;
+ TInt bytesRecorded = 0;
+ TInt bytesPlayed = 0;
+
+ TRequestStatus stat[3]; // 1 record + 2 play request statuses
+ TInt length;
+ TInt activePlayOffset[2]; // To keep track of the buffer offset for each active play request.
+ RQueue<TInt> playQueue; // A list containing the offsets for any buffer which is waiting to be played.
+
+ // Issue three record requests and wait for them to complete.
+ TInt retOffset;
+ for (i=0 ; i<3 ; i++)
+ {
+ RxSoundDevice.RecordData(stat[2],length);
+ User::WaitForRequest(stat[2]);
+ retOffset=stat[2].Int();
+// Test.Printf(_L("RECORD(%d)-Buf %d\r\n"),i,retOffset);
+ CHECK_POSITIVE(retOffset);
+ CHECK(length==bufSize);
+ bytesRecorded += length;
+ playQueue.PushL(retOffset);
+ remainingRecordCount--;
+ Test.Printf(_L("."));
+ }
+
+ // Start playing first two buffers
+ TUint flags=0;
+ activePlayOffset[0]=playQueue.PopL();
+ TxSoundDevice.PlayData(stat[0],activePlayOffset[0],bufSize,flags);
+ activePlayOffset[1]=playQueue.PopL();
+ TxSoundDevice.PlayData(stat[1],activePlayOffset[1],bufSize,flags);
+
+ // Now queue the next record request.
+ RxSoundDevice.RecordData(stat[2],length);
+
+ do
+ {
+ // Wait for the next request to complete.
+ User::WaitForAnyRequest();
+
+ // Work out which request this applies to.
+ for (i=0;i<3;i++)
+ {
+ if (stat[i]!=KRequestPending)
+ break;
+ }
+ CHECK(i<3);
+
+ if (i==2)
+ {
+ // It is the record request that has completed
+ remainingRecordCount--;
+ retOffset=stat[2].Int();
+// Test.Printf(_L("RECORD(%d)-Buf %d\r\n"),remainingRecordCount,retOffset);
+ CHECK_POSITIVE(retOffset);
+ CHECK(length==bufSize);
+ bytesRecorded += length;
+ Test.Printf(_L("."));
+
+ // Add the buffer to playQueue
+ playQueue.PushL(retOffset);
+
+ // If we haven't recorded enough data yet then record some more.
+ if (remainingRecordCount>0)
+ RxSoundDevice.RecordData(stat[2],length);
+ else
+ {
+ Test.Printf(_L("***Disabling stat[2]\r\n"));
+ stat[2]=KRequestPending;
+ }
+ }
+ else
+ {
+ // Its one of the play requests that have completed
+ if(stat[i].Int() >= 0)
+ {
+ // release the buffer.
+// Test.Printf(_L("PLAY(%d) i%d CompBuf %d\r\n"),remainingPlayCount-1,i,activePlayOffset[i]);
+ r=RxSoundDevice.ReleaseBuffer(activePlayOffset[i]);
+ CHECK_NOERROR(r);
+ Test.Printf(_L("*"));
+ }
+ else
+ {
+ // Play failed - but we ignore underflow because it often happens on WDP roms.
+ CHECK(stat[i].Int() == KErrUnderflow);
+ Test.Printf(_L("U"));
+ }
+
+ remainingPlayCount--;
+ bytesPlayed += bufSize;
+
+ // If there are buffers available then issue a further play request and update the 'next to play' list.
+ if (playQueue.Count() != 0)
+ {
+ activePlayOffset[i]=playQueue.PopL();
+
+// Test.Printf(_L("PLAY(%d) i%d NextBuf%d\r\n"),remainingPlayCount,i,activePlayOffset[i]);
+ flags=(remainingPlayCount<=2)?KSndFlagLastSample:0;
+ TxSoundDevice.PlayData(stat[i],activePlayOffset[i],bufSize,flags);
+ }
+ else
+ {
+ Test.Printf(_L("***Disabling stat[%d]\r\n"), i, stat[i].Int());
+ stat[i]=KRequestPending;
+ }
+ }
+ }
+ while (remainingRecordCount>0 || remainingPlayCount>0);
+ playQueue.Close();
+ CHECK_EQUAL(bytesToTransfer,bytesRecorded);
+ CHECK_EQUAL(bytesToTransfer,bytesPlayed);
+
+ RxSoundDevice.CancelRecordData(); // Stop the driver from recording.
+ chunk.Close();
+
+ Test.Printf(_L("\nSimultaneous test ends\r\n"));
+ return;
+ }
+
+void TestSpeed()
+ {
+ Test.Next(_L("Preparing to measure record/playback speed..."));
+ TInt r = KErrNone;
+ TInt i;
+ // Setup the same sound configuration for both - record and play channels
+ if (RecordCapsBuf().iEncodings & KSoundEncoding16BitPCM)
+ RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+
+ if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+
+ RecordFormatBuf().iChannels = 2;
+ PlayFormatBuf().iChannels = 2;
+
+ // find first supported rate and set the the audio configuration to use it
+ for (i=0 ; i <= (TInt)ESoundRate48000Hz ; i++)
+ {
+ // check record channel
+ RecordFormatBuf().iRate = (TSoundRate)i;
+ r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ if (RecordCapsBuf().iRates & (1 << i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+
+ // ..and try the same bitrate for playback
+ PlayFormatBuf().iRate = (TSoundRate)i;
+ r = TxSoundDevice.SetAudioFormat(PlayFormatBuf);
+ if (PlayCapsBuf().iRates & (1 << i))
+ {
+ CHECK_NOERROR(r); // Caps reports it is supported
+ break;
+ }
+ }
+ }
+
+ // both channels are set at this point, continue
+ PrintConfig(RecordFormatBuf(),Test);
+ PrintConfig(PlayFormatBuf(),Test);
+
+ // Set the volume level in both channels
+ RxSoundDevice.SetVolume(KSoundMaxVolume);
+ TxSoundDevice.SetVolume(KSoundMaxVolume - 10);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize=BytesPerSecond(RecordFormatBuf())/8; // Large enough to hold 1/8th second of data.
+ bufSize=ValidBufferSize(bufSize,RecordCapsBuf().iRequestMinSize,RecordFormatBuf()); // Keep the buffer length valid for driver.
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=7+7; // Must be able to use less than this
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ // Assign the same chunk to the play channel.
+ r=TxSoundDevice.SetBufferChunkOpen(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+
+ Test.Next(_L("Starting recording speed test..."));
+ TInt length;
+
+ // Recording speed test
+ TTime preTime, postTime;
+ preTime.UniversalTime();
+ for(i=0; i<100; ++i)
+ {
+ TRequestStatus s;
+ length = -1;
+
+ TTime preBufTime, postBufTime;
+ preBufTime.UniversalTime();
+ RxSoundDevice.RecordData(s, length);
+ User::WaitForRequest(s);
+
+ postBufTime.UniversalTime();
+ TTimeIntervalMicroSeconds elapsedBufTime = postBufTime.MicroSecondsFrom(preBufTime);
+ Test.Printf(_L("\tElapsed buf (%d/100) recording time %d\n"), i, elapsedBufTime.Int64());
+ CHECK(s.Int() >= 0);
+ CHECK(RxSoundDevice.ReleaseBuffer(s.Int()) == KErrNone);
+ CHECK(length == bufSize);
+ }
+ postTime.UniversalTime();
+ TTimeIntervalMicroSeconds elapsedRecordingTime = postTime.MicroSecondsFrom(preTime);
+ Test.Printf(_L("Elapsed recording time %d\n"), elapsedRecordingTime.Int64());
+ Test.Printf(_L("Record timing done\n"));
+
+
+ //
+ // Playback test
+ //
+ TxSoundDevice.CancelPlayData();
+ struct RequestInfo {
+ TRequestStatus s_m;
+ TUint bufOffset_m;
+ };
+ RequestInfo requestA;
+ RequestInfo requestB;
+
+ // Get two buffers for playback speed test
+ RxSoundDevice.RecordData(requestA.s_m, length);
+ User::WaitForRequest(requestA.s_m);
+ CHECK(requestA.s_m.Int() >= 0);
+ requestA.bufOffset_m = requestA.s_m.Int();
+
+ RxSoundDevice.RecordData(requestB.s_m, length);
+ User::WaitForRequest(requestB.s_m);
+ CHECK(requestB.s_m.Int() >= 0);
+ requestB.bufOffset_m = requestB.s_m.Int();
+
+ Test.Printf(_L("buf offsets %d %d\n"), requestA.bufOffset_m, requestB.bufOffset_m);
+
+ RequestInfo *prevRequest = &requestA;
+ RequestInfo *currRequest = &requestB;
+
+ // Issue initial play request
+ TxSoundDevice.PlayData(prevRequest->s_m, prevRequest->bufOffset_m, bufSize);
+
+ preTime.UniversalTime();
+ for(i=0; i<100; ++i)
+ {
+ // Issue new request so we do not underflow....
+ TxSoundDevice.PlayData(currRequest->s_m, currRequest->bufOffset_m, bufSize, (i==99)?(KSndFlagLastSample) : (0));
+
+ // Wait for previous request to complete
+ TTime preBufTime, postBufTime;
+ preBufTime.UniversalTime();
+ User::WaitForRequest(prevRequest->s_m);
+ CHECK_NOERROR(prevRequest->s_m.Int());
+
+ postBufTime.UniversalTime();
+ TTimeIntervalMicroSeconds elapsedBufTime = postBufTime.MicroSecondsFrom(preBufTime);
+ Test.Printf(_L("\tElapsed buf (%d/100) playback time %d\n"), i, elapsedBufTime.Int64());
+
+ // Swap previous and current requests
+ RequestInfo *p = prevRequest;
+ prevRequest = currRequest;
+ currRequest = p;
+ }
+
+ postTime.UniversalTime();
+ TTimeIntervalMicroSeconds elapsedPlaybackTime = postTime.MicroSecondsFrom(preTime);
+ Test.Printf(_L("Elapsed playback time = %d us\n"), elapsedPlaybackTime.Int64());
+ Test.Printf(_L("Elapsed recording time = %d us\n"), elapsedRecordingTime.Int64());
+
+ double play = (double) elapsedPlaybackTime.Int64();
+ double record = (double) elapsedRecordingTime.Int64();
+ Test.Printf(_L("difference %f%%\n"), (play*100)/record);
+
+ User::WaitForRequest(prevRequest->s_m);
+ CHECK_NOERROR(prevRequest->s_m.Int());
+
+ // Free the two buffers
+ CHECK(RxSoundDevice.ReleaseBuffer(requestA.bufOffset_m) == KErrNone);
+ CHECK(RxSoundDevice.ReleaseBuffer(requestB.bufOffset_m) == KErrNone);
+
+ Test.Printf(_L("Playback done\n"));
+ TxSoundDevice.CancelPlayData();
+ RxSoundDevice.CancelPlayData();
+
+ chunk.Close();
+ return;
+}
+
+#ifdef __WINS__
+void TestDefectDTWMM00678()
+{
+ // DTW-MM00678 RSoundSc::RecordData() returns recorded length > allocated buffer size
+ TRequestStatus status[3];
+ TInt length[3];
+ Test.Next(_L("DTW-MM00678 RSoundSc::RecordData() returns recorded length > allocated buffer size"));
+
+ // Make sure recording is not in progress
+ RxSoundDevice.CancelRecordData();
+
+ TInt r = KErrNone;
+ TInt i;
+ // Setup the same sound configuration for both - record and play channels
+ 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++)
+ {
+ // check record channel
+ RecordFormatBuf().iRate = (TSoundRate)i;
+ if (RecordCapsBuf().iRates & (1 << i))
+ {
+ // Caps reports it is supported
+ r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ CHECK_NOERROR(r);
+ break;
+ }
+ }
+ // Check we found/set a valid format
+ CHECK(i <= ESoundRate48000Hz);
+
+ // Set recording format
+ PrintConfig(RecordFormatBuf(),Test);
+
+ // Set the volume level
+ RxSoundDevice.SetVolume(KSoundMaxVolume);
+
+ // Set the record buffer configuration, then read it back.
+ RChunk chunk;
+ TInt bufSize = 64 * 1024; // The defect is seen, on windows, when the buffer size is 64k and the LDD does 2x 32k transfers per buffer
+ TTestSharedChunkBufConfig bufferConfig;
+ bufferConfig.iNumBuffers=7;
+ 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);
+
+ // Calculate time required to fill a single 64k byte buffer
+ TUint32 durationOneBufferMsec = (1000 * bufSize) / BytesPerSecond(RecordFormatBuf());
+ Test.Printf(_L("durationOneBufferMsec %d\n"), durationOneBufferMsec);
+
+ // Start recording....
+ Test.Printf(_L("Issue 3 RecordData requests then wait to pause during second internal 32k internal transfers of the second buffer...\n"));
+ for(i=0; i<3; ++i)
+ {
+ RxSoundDevice.RecordData(status[i], length[i]);
+ }
+
+ // Wait for 1 3/4 64k buffers. In other words, wait for 3.75x32k byte internal transfers so we pause during the second transfer of the second buffer
+ User::After(durationOneBufferMsec *1000 * (1 + 3/4) );
+
+ CHECK_NOERROR(RxSoundDevice.Pause());
+ Test.Printf(_L("Paused\n"));
+
+ for(i=0; i<3; ++i)
+ {
+ User::WaitForRequest(status[i]);
+ Test.Printf(_L("status[%d].Int() = %d\n"), i, status[i].Int());
+ Test.Printf(_L("length[%d] = %d\n"), i, length[i]);
+ }
+
+ bool testValid = true;
+
+ if((status[0].Int() < 0) || (length[0] != bufSize))
+ {
+ testValid = false;
+ Test.Printf(_L("Test invalid because pause hit first request\n"));
+ }
+
+ if(testValid && (status[1].Int() == KErrCancel))
+ {
+ testValid = false;
+ Test.Printf(_L("Test invalid because pause hit before second request started\n"));
+ }
+
+ if(testValid && (status[2].Int() != KErrCancel))
+ {
+ testValid = false;
+ Test.Printf(_L("Test invalid because pause missed all requests\n"));
+ }
+
+ if(testValid)
+ {
+ Test.Printf(_L("Appear to have issued pause at the correct time, check results\n"));
+ // First request should have completed with a full buffer of data
+ CHECK(status[0].Int() >= 0);
+ CHECK(length[0] == bufSize);
+
+ // second request should have been truncated
+ CHECK(status[1].Int() >= 0);
+ CHECK(length[1] < bufSize);
+
+ // Last request should have been cancelled.
+ CHECK(status[2].Int() == KErrCancel);
+ }
+ Test.Printf(_L("DTW-MM00678 test done\r\n"));
+
+ //CHECK_NOERROR(RxSoundDevice.Resume());
+
+ // Make sure recording is not in progress
+ RxSoundDevice.CancelRecordData();
+ TxSoundDevice.CancelPlayData();
+
+ chunk.Close();
+ return;
+ }
+#endif
+
+LOCAL_C void TestUnloadDrivers()
+ {
+ TInt r=User::FreeLogicalDevice(KDevSoundScName);
+ Test.Printf(_L("Unloading %S.LDD - %d\r\n"),&KDevSoundScName,r);
+ CHECK_NOERROR(r);
+
+ 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);
+ }
+ }
+
+void TestTimePlayed()
+ {
+ TTimeIntervalMicroSecondsBuf timeIntervalBuf;
+
+ // Don't try to do the tests if TimePlayed() is not supported
+ TInt r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ if (r == KErrNotSupported)
+ {
+ Test.Printf(_L("TimePlayed() is not supported, skipping tests\n"));
+ return;
+ }
+ CHECK_NOERROR(r);
+
+ TInt rate;
+
+ // Find first supported rate and set the the audio configuration to use it
+ for (rate = 0; rate <= ESoundRate48000Hz; ++rate)
+ {
+ if (PlayCapsBuf().iRates & (1 << rate))
+ {
+ break;
+ }
+ }
+
+ // Test mono and Stereo
+ for (TInt channels=1; channels<=2; ++channels)
+ {
+ TRequestStatus stat[2];
+
+ Test.Next(_L("Preparing to play..."));
+ if (PlayCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ PlayFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+ PlayFormatBuf().iRate = (TSoundRate) rate;
+ PlayFormatBuf().iChannels = channels;
+ PrintConfig(PlayFormatBuf(),Test);
+ r = TxSoundDevice.SetAudioFormat(PlayFormatBuf);
+ CHECK_NOERROR(r);
+
+ // Set the play buffer configuration, then read it back.
+ 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=2;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=TxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ TxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+ TPtr8* tPtr[2];
+ TInt i;
+ for (i=0;i<2;i++)
+ tPtr[i]=new TPtr8(chunk.Base()+bufferConfig.iBufferOffsetList[i],bufSize);
+
+
+ r=MakeSineTable(PlayFormatBuf());
+ CHECK_NOERROR(r);
+ r=SetToneFrequency(440,PlayFormatBuf());
+ CHECK_NOERROR(r);
+
+ WriteTone(*tPtr[0],PlayFormatBuf());
+ WriteTone(*tPtr[1],PlayFormatBuf());
+
+ // set up a timer to interrogate time played
+ TRequestStatus timerStat;
+ RTimer timer;
+ timer.CreateLocal();
+ TTimeIntervalMicroSeconds32 timerInterval(50000);
+
+ TInt64 currentTime, previousTime;
+
+ Test.Next(_L("Time Played..."));
+
+ currentTime = previousTime = MAKE_TINT64(0,0);
+
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,0);
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],bufSize,KSndFlagLastSample);
+
+ // check requests are pending
+ CHECK_EQUAL(stat[0].Int(),KRequestPending);
+ CHECK_EQUAL(stat[1].Int(),KRequestPending);
+
+ // check time recorded is not supported for play channel
+ CHECK(TxSoundDevice.TimeRecorded(timeIntervalBuf)==KErrNotSupported);
+
+ timer.After(timerStat,timerInterval);
+ // first buffer
+ while (stat[0] == KRequestPending)
+ {
+ User::WaitForRequest(stat[0],timerStat);
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ CHECK_EQUAL(stat[0].Int(),KErrNone);
+
+ timer.After(timerStat,timerInterval);
+ // second buffer
+ while (stat[1] == KRequestPending)
+ {
+ User::WaitForRequest(stat[1],timerStat);
+ Test.Printf(_L("stat[1] %x, timerStat %x\n"),stat[1].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ if (stat[1] == KRequestPending) // still playing
+ {
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+ }
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[1] %x, timerStat %x\n"),stat[1].Int(),timerStat.Int());
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(timeIntervalBuf().Int64()),I64LOW(timeIntervalBuf().Int64()));
+
+ CHECK_EQUAL(stat[1].Int(),KErrNone);
+
+ //
+ // Time Played with pause
+ //
+
+ Test.Next(_L("Time Played with pause..."));
+
+ TTimeIntervalMicroSeconds32 pauseInterval(2000000);
+ TBool paused = EFalse;
+
+ currentTime = previousTime = MAKE_TINT64(0,0);
+ timer.Cancel();
+
+ TxSoundDevice.PlayData(stat[0],bufferConfig.iBufferOffsetList[0],bufSize,0);
+ TxSoundDevice.PlayData(stat[1],bufferConfig.iBufferOffsetList[1],bufSize,KSndFlagLastSample);
+
+ // check requests are pending
+ CHECK_EQUAL(stat[0].Int(),KRequestPending);
+ CHECK_EQUAL(stat[1].Int(),KRequestPending);
+
+ // check time recorded is not supported for play channel
+ CHECK(TxSoundDevice.TimeRecorded(timeIntervalBuf)==KErrNotSupported);
+
+ timer.After(timerStat,timerInterval);
+ // first buffer
+ while (stat[0] == KRequestPending)
+ {
+ User::WaitForRequest(stat[0],timerStat);
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+
+ // Pause and resume ...
+ if (paused == EFalse && I64LOW(currentTime) > 500000)
+ {
+ paused = ETrue;
+ TxSoundDevice.Pause();
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ TInt64 pausedTime1 = timeIntervalBuf().Int64();
+ Test.Printf(_L("Paused time_high %d, time_low %d\n"),I64HIGH(pausedTime1),I64LOW(pausedTime1));
+
+ User::After(pauseInterval);
+
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ TInt64 pausedTime2 = timeIntervalBuf().Int64();
+ Test.Printf(_L("Resumed time_high %d, time_low %d\n"),I64HIGH(pausedTime2),I64LOW(pausedTime2));
+ //CHECK(pausedTime1 == pausedTime2);
+ TxSoundDevice.Resume();
+ }
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ CHECK_EQUAL(stat[0].Int(),KErrNone);
+
+ timer.After(timerStat,timerInterval);
+ // second buffer
+ while (stat[1] == KRequestPending)
+ {
+ User::WaitForRequest(stat[1],timerStat);
+ Test.Printf(_L("stat[1] %x, timerStat %x\n"),stat[1].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ if (stat[1] == KRequestPending) // still playing
+ {
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+ }
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[1] %x, timerStat %x\n"),stat[1].Int(),timerStat.Int());
+ r = TxSoundDevice.TimePlayed(timeIntervalBuf);
+ CHECK_NOERROR(r);
+
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(timeIntervalBuf().Int64()),I64LOW(timeIntervalBuf().Int64()));
+
+ CHECK_EQUAL(stat[1].Int(),KErrNone);
+
+ // clean up
+ timer.Close();
+ chunk.Close();
+ for (i=0;i<2;i++)
+ delete tPtr[i];
+
+ } // channel loop
+ }
+
+void TestTimeRecorded()
+ {
+ TTimeIntervalMicroSecondsBuf timeIntervalBuf;
+
+ TInt r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ if (r == KErrNotSupported)
+ {
+ Test.Printf(_L("TimeRecorded() is not supported, skipping tests\n"));
+ return;
+ }
+ CHECK_NOERROR(r);
+
+ TInt rate;
+
+ // Find first supported rate and set the the audio configuration to use it
+ for (rate = 0; rate <= ESoundRate48000Hz; ++rate)
+ {
+ if (PlayCapsBuf().iRates & (1 << rate))
+ {
+ break;
+ }
+ }
+
+ // Test mono and Stereo
+ for (TInt channels=1; channels<=2; ++channels)
+ {
+ TRequestStatus stat[2];
+
+ Test.Next(_L("Preparing to record..."));
+ if (RecordCapsBuf().iEncodings&KSoundEncoding16BitPCM)
+ RecordFormatBuf().iEncoding = ESoundEncoding16BitPCM;
+ RecordFormatBuf().iRate = (TSoundRate) rate;
+ RecordFormatBuf().iChannels = channels;
+ PrintConfig(RecordFormatBuf(),Test);
+ r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ CHECK_NOERROR(r);
+
+ // Set the play buffer configuration, then read it back.
+ 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=4;
+ bufferConfig.iBufferSizeInBytes=bufSize;
+ bufferConfig.iFlags=0; // All buffers will be contiguous
+ TPckg<TTestSharedChunkBufConfig> bufferConfigBuf(bufferConfig);
+ r=RxSoundDevice.SetBufferChunkCreate(bufferConfigBuf,chunk);
+ CHECK_NOERROR(r);
+ RxSoundDevice.GetBufferConfig(bufferConfigBuf);
+ PrintBufferConf(bufferConfig,Test);
+ CHECK(bufferConfig.iBufferSizeInBytes==bufSize);
+
+ // set up a timer to interrogate time played
+ TRequestStatus timerStat;
+ RTimer timer;
+ timer.CreateLocal();
+ TTimeIntervalMicroSeconds32 timerInterval(50000);
+
+ TInt64 currentTime, previousTime;
+
+ Test.Next(_L("Time Recorded..."));
+
+ currentTime = previousTime = MAKE_TINT64(0,0);
+
+ TInt length1=0, length2=0;
+ RxSoundDevice.RecordData(stat[0],length1);
+ RxSoundDevice.RecordData(stat[1],length2);
+
+ // check requests are pending
+ CHECK_EQUAL(stat[0].Int(),KRequestPending);
+ CHECK_EQUAL(stat[1].Int(),KRequestPending);
+
+ // check time played is not supported for record channel
+ CHECK(RxSoundDevice.TimePlayed(timeIntervalBuf)==KErrNotSupported);
+
+ timer.After(timerStat,timerInterval);
+ // first buffer
+ while (stat[0] == KRequestPending)
+ {
+ User::WaitForRequest(stat[0],timerStat);
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ CHECK(stat[0].Int() == 0);
+
+ timer.After(timerStat,timerInterval);
+ // second buffer
+ while (stat[1] == KRequestPending)
+ {
+ User::WaitForRequest(stat[1],timerStat);
+ Test.Printf(_L("stat[1] %x, timerStat %x\n"),stat[1].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ if (stat[1] == KRequestPending) // still playing
+ {
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+ }
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[1] %x, timerStat %x\n"),stat[1].Int(),timerStat.Int());
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(timeIntervalBuf().Int64()),I64LOW(timeIntervalBuf().Int64()));
+
+ CHECK(stat[1].Int() > 0);
+
+ // stop recording into the next buffer
+ RxSoundDevice.CancelRecordData();
+
+ // Release the buffers
+ r = RxSoundDevice.ReleaseBuffer(stat[0].Int());
+ CHECK_EQUAL(r, KErrNone);
+ r = RxSoundDevice.ReleaseBuffer(stat[1].Int());
+ CHECK_EQUAL(r, KErrNone);
+
+ //
+ // Time Recorded with pause
+ //
+
+ Test.Next(_L("Time Recorded with pause..."));
+
+ TTimeIntervalMicroSeconds32 pauseInterval(2000000);
+ TBool paused = EFalse;
+
+ currentTime = previousTime = MAKE_TINT64(0,0);
+
+ // Record and discard some data to make sure all testing is not within the first buffer...
+ RxSoundDevice.RecordData(stat[0],length1);
+ User::WaitForRequest(stat[0]);
+ CHECK(stat[0].Int() >= 0);
+ RxSoundDevice.ReleaseBuffer(stat[0].Int());
+
+ RxSoundDevice.RecordData(stat[0],length1);
+ RxSoundDevice.RecordData(stat[1],length2);
+
+ // check requests are pending
+ CHECK_EQUAL(stat[0].Int(),KRequestPending);
+
+ // check time recorded is not supported for play channel
+ CHECK(RxSoundDevice.TimePlayed(timeIntervalBuf)==KErrNotSupported);
+
+ timer.After(timerStat,timerInterval);
+ // first buffer
+ while (stat[0] == KRequestPending)
+ {
+ User::WaitForRequest(stat[0],timerStat);
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+
+ // Pause and resume ...
+ if (paused == EFalse && I64LOW(currentTime) > 500000)
+ {
+ paused = ETrue;
+ RxSoundDevice.Pause();
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ TInt64 pausedTime1 = timeIntervalBuf().Int64();
+ Test.Printf(_L("Paused time_high %d, time_low %d\n"),I64HIGH(pausedTime1),I64LOW(pausedTime1));
+ // Check time is increasing
+ CHECK((I64LOW(pausedTime1) >= I64LOW(currentTime)));
+
+ User::After(pauseInterval);
+
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ TInt64 pausedTime2 = timeIntervalBuf().Int64();
+ Test.Printf(_L("Resumed time_high %d, time_low %d\n"),I64HIGH(pausedTime2),I64LOW(pausedTime2));
+ // Check time is unchanged
+ CHECK((I64LOW(pausedTime2) == I64LOW(pausedTime1)));
+ }
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+ }
+
+ timer.Cancel();
+
+ // Buffer should complete normally or be empty (indicated by KErrCancel)
+ CHECK((stat[0].Int() >= 0) || (stat[0].Int() == KErrCancel));
+ // Release the first buffer, if it contained any data
+ if (stat[0].Int() >= 0)
+ {
+ r = RxSoundDevice.ReleaseBuffer(stat[0].Int());
+ CHECK_EQUAL(r, KErrNone);
+ }
+ // Check second buffer completed or cancelled
+ User::WaitForRequest(stat[1]);
+ CHECK_EQUAL(stat[1].Int(), KErrCancel);
+
+ // Now resume the recording
+ r = RxSoundDevice.Resume();
+ CHECK_EQUAL(r, KErrNone);
+
+ // Need to re-setup buffers
+ RxSoundDevice.RecordData(stat[0],length1);
+ RxSoundDevice.RecordData(stat[1],length2);
+
+ timer.After(timerStat,timerInterval);
+ // another buffer
+ while (stat[0] == KRequestPending)
+ {
+ User::WaitForRequest(stat[0],timerStat);
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ previousTime = currentTime;
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(currentTime),I64LOW(currentTime));
+
+ // ensure time is increasing or function is not supported
+ if (stat[0] == KRequestPending) // still recording
+ {
+ CHECK((I64LOW(currentTime) >= I64LOW(previousTime)) || r == KErrNotSupported);
+ }
+
+ if (timerStat != KRequestPending)
+ {
+ timer.After(timerStat,timerInterval);
+ }
+
+ }
+ timer.Cancel();
+
+ Test.Printf(_L("stat[0] %x, timerStat %x\n"),stat[0].Int(),timerStat.Int());
+ r = RxSoundDevice.TimeRecorded(timeIntervalBuf);
+ CHECK_NOERROR(r);
+ currentTime = timeIntervalBuf().Int64();
+ Test.Printf(_L("time_high %d, time_low %d\n"),I64HIGH(timeIntervalBuf().Int64()),I64LOW(timeIntervalBuf().Int64()));
+
+ CHECK(stat[0].Int() > 0);
+
+ // stop recording into the next buffer
+ RxSoundDevice.CancelRecordData();
+
+ // Release the buffers
+ r = RxSoundDevice.ReleaseBuffer(stat[0].Int());
+ CHECK_EQUAL(r, KErrNone);
+
+ // clean up
+ timer.Close();
+ chunk.Close();
+ } // channel loop
+ }
+
+TInt E32Main()
+ {
+// User::SetDebugMask(0x10,1); // Enable KSOUND1
+
+ __UHEAP_MARK;
+ TInt r;
+
+ 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);
+ }
+
+ __KHEAP_MARK;
+
+ /** @SYMTestCaseID PBASE-T_SOUND2-223
+ @SYMTestCaseDesc Opening the channel - normal
+ @SYMTestPriority Critical
+ @SYMTestActions 1) With the LDD and PDD installed and with all channels closed on the device,
+ open a channel for playback on the device.
+ 2) Without closing the playback channel, open a channel for record on the device.
+ 3) Close the playback channel and then open it again.
+ 4) Close the record channel and then open it again.
+ @SYMTestExpectedResults 1) KErrNone - Channel opens successfully.
+ 2) KErrNone - Channel opens successfully.
+ 3) KErrNone - Channel re-opens successfully.
+ 4) KErrNone - Channel re-opens successfully.
+ @SYMREQ PREQ1073.4 */
+
+ 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("Close playback channel"));
+ TxSoundDevice.Close();
+ Test.Next(_L("Re-open playback channel"));
+ r = TxSoundDevice.Open(KSoundScTxUnit0);
+ CHECK_NOERROR(r);
+ Test.Next(_L("Close record channel"));
+ RxSoundDevice.Close();
+ Test.Next(_L("Re-open record channel"));
+ r = RxSoundDevice.Open(KSoundScRxUnit0);
+ CHECK_NOERROR(r);
+
+ Test.Next(_L("Query play formats supported"));
+ TxSoundDevice.Caps(PlayCapsBuf);
+ PrintCaps(playCaps,Test);
+
+ Test.Next(_L("Query record formats supported"));
+ RxSoundDevice.Caps(RecordCapsBuf);
+ TSoundFormatsSupportedV02 recordCaps=RecordCapsBuf();
+ PrintCaps(recordCaps,Test);
+
+ Test.Next(_L("Query current play settings"));
+ TxSoundDevice.AudioFormat(PlayFormatBuf);
+ TCurrentSoundFormatV02 playFormat=PlayFormatBuf();
+ PrintConfig(playFormat,Test);
+ CheckConfig(playFormat,playCaps);
+
+ Test.Next(_L("Query current record settings"));
+ RxSoundDevice.AudioFormat(RecordFormatBuf);
+ TCurrentSoundFormatV02 recordFormat=RecordFormatBuf();
+ PrintConfig(recordFormat,Test);
+ CheckConfig(recordFormat,recordCaps);
+
+ Test.Next(_L("Set play format"));
+ if (playCaps.iEncodings&KSoundEncoding16BitPCM)
+ playFormat.iEncoding = ESoundEncoding16BitPCM;
+ PrintConfig(playFormat,Test);
+ r = TxSoundDevice.SetAudioFormat(PlayFormatBuf);
+ CHECK_NOERROR(r);
+
+ Test.Next(_L("Set Record Format"));
+ if (recordCaps.iEncodings&KSoundEncoding16BitPCM)
+ recordFormat.iEncoding = ESoundEncoding16BitPCM;
+ PrintConfig(recordFormat,Test);
+ r = RxSoundDevice.SetAudioFormat(RecordFormatBuf);
+ CHECK_NOERROR(r);
+
+#ifdef SOAKTEST
+ TInt freeRamInBytes=0;
+ TTime stim;
+ stim.HomeTime();
+
+ FOREVER
+ {
+#endif
+
+ TestBasicPlayFunctions();
+ TestBasicRecordFunctions();
+ TestPlayAllRates(1,4);
+ TestPlayAllRates(2,4);
+ TestRecordAllRates(1,4);
+ TestRecordAllRates(2,4);
+ TestRecordVolume(2,10);
+ TestPlayCancel();
+ TestRecordCancel();
+ TestRecordPauseResume(1);
+ TestRecordPauseResume(2);
+ TestSimultaneousPlayRecord();
+ TestTimePlayed();
+ TestTimeRecorded();
+#ifdef __WINS__
+ TestDefectDTWMM00678();
+#endif
+ //TestSpeed(); // Gives information which may help debug h4 FMM issues
+
+#ifdef SOAKTEST
+ TInt free;
+ HAL::Get(HAL::EMemoryRAMFree,free);
+ Test.Printf(_L("Free ram is %d bytes\r\n"),free);
+// if (freeRamInBytes)
+// CHECK(freeRamInBytes == free)
+ freeRamInBytes=free;
+
+ TTime ntim;
+ ntim.HomeTime();
+ TTimeIntervalMinutes elapsed;
+ r=ntim.MinutesFrom(stim,elapsed);
+ CHECK_NOERROR(r);
+ Test.Printf(_L("Test has been running for %d minutes\r\n"),elapsed.Int());
+ }
+#endif
+
+ 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;
+ User::Allocator().Check();
+ return(KErrNone);
+ }