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