diff -r 000000000000 -r 96e5fb8b040d kerneltest/e32test/multimedia/t_sound2.cpp --- /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 +#include "t_soundutils.h" +#include +#include +#include + +// #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< 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< 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 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 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< 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 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< 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 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]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 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 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 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 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 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 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 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 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); + }