sl@0: // Copyright (c) 2006-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_soundmchan.cpp sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file Testing access to the shared chunk sound driver from multiple user side threads. sl@0: */ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include "t_soundutils.h" sl@0: sl@0: RTest Test(_L("T_SOUNDMCHAN")); sl@0: sl@0: const TInt KHeapSize=0x4000; sl@0: sl@0: enum TSecThreadTestId sl@0: { sl@0: ESecThreadConfigPlayback, sl@0: ESecThreadConfigRecord, sl@0: }; sl@0: struct SSecondaryThreadInfo sl@0: { sl@0: TSecThreadTestId iTestId; sl@0: // TInt iExpectedRetVal; sl@0: TThreadId iThreadId; sl@0: TInt iDrvHandle; sl@0: }; sl@0: sl@0: _LIT(KSndLddFileName,"ESOUNDSC.LDD"); sl@0: _LIT(KSndPddFileName,"SOUNDSC.PDD"); sl@0: sl@0: sl@0: LOCAL_C TInt secondaryThread(TAny* aTestInfo) sl@0: { sl@0: RTest stest(_L("Secondary test thread")); sl@0: stest.Title(); sl@0: sl@0: stest.Start(_L("Check which test to perform")); sl@0: SSecondaryThreadInfo& sti=*((SSecondaryThreadInfo*)aTestInfo); sl@0: TInt r; sl@0: switch(sti.iTestId) sl@0: { sl@0: case ESecThreadConfigPlayback: sl@0: { sl@0: stest.Next(_L("Duplicate the channel handle passed from main thread")); sl@0: sl@0: // Get a reference to the main thread - which created the handle sl@0: RThread thread; sl@0: r=thread.Open(sti.iThreadId); sl@0: stest(r==KErrNone); sl@0: sl@0: // Duplicate the driver handle passed from the other thread - for this thread sl@0: RSoundSc snddev; sl@0: snddev.SetHandle(sti.iDrvHandle); sl@0: r=snddev.Duplicate(thread); sl@0: stest(r==KErrNone); sl@0: thread.Close(); sl@0: sl@0: stest.Next(_L("Configure the driver")); sl@0: // Read the capabilties of this device. sl@0: TSoundFormatsSupportedV02Buf capsBuf; sl@0: snddev.Caps(capsBuf); sl@0: TSoundFormatsSupportedV02& caps=capsBuf(); sl@0: sl@0: // Read back the default configuration - which must be valid. sl@0: TCurrentSoundFormatV02Buf formatBuf; sl@0: snddev.AudioFormat(formatBuf); sl@0: TCurrentSoundFormatV02& format=formatBuf(); sl@0: sl@0: if (caps.iEncodings&KSoundEncoding16BitPCM) sl@0: format.iEncoding = ESoundEncoding16BitPCM; sl@0: if (caps.iRates&KSoundRate16000Hz) sl@0: format.iRate = ESoundRate16000Hz; sl@0: if (caps.iChannels&KSoundStereoChannel) sl@0: format.iChannels = 2; sl@0: r=snddev.SetAudioFormat(formatBuf); sl@0: stest(r==KErrNone); sl@0: r=snddev.SetVolume(KSoundMaxVolume); sl@0: stest(r==KErrNone); sl@0: sl@0: stest.Next(_L("Close the channel again")); sl@0: snddev.Close(); sl@0: sl@0: break; sl@0: } sl@0: sl@0: case ESecThreadConfigRecord: sl@0: { sl@0: stest.Next(_L("Use the channel passed from main thread to configure driver")); sl@0: sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: // stest.Getch(); sl@0: stest.End(); sl@0: return(KErrNone); sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: sl@0: { sl@0: __UHEAP_MARK; sl@0: sl@0: Test.Title(); sl@0: sl@0: TInt r; sl@0: Test.Start(_L("Load sound PDD")); sl@0: r=User::LoadPhysicalDevice(KSndPddFileName); sl@0: if (r==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: Test(r==KErrNone || r==KErrAlreadyExists); sl@0: sl@0: Test.Next(_L("Load sound LDD")); sl@0: r=User::LoadLogicalDevice(KSndLddFileName); sl@0: Test(r==KErrNone || r==KErrAlreadyExists); sl@0: sl@0: /** @SYMTestCaseID PBASE-T_SOUNDMCHAN-224 sl@0: @SYMTestCaseDesc Opening the channel - more than one channel 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 first playback channel, attempt to open a second channel sl@0: for playback on the same device. sl@0: @SYMTestExpectedResults 1) KErrNone - Channel opens successfully. sl@0: 2) Should fail with KErrInUse. sl@0: @SYMREQ PREQ1073.4 */ sl@0: sl@0: __KHEAP_MARK; sl@0: sl@0: Test.Next(_L("Open a channel on the play device")); sl@0: RSoundSc snddev; sl@0: r=snddev.Open(KSoundScTxUnit0); sl@0: Test(r==KErrNone); sl@0: sl@0: Test.Next(_L("Try opening the same unit a second time.")); sl@0: RSoundSc snddev2; sl@0: r=snddev2.Open(KSoundScTxUnit0); sl@0: Test(r==KErrInUse); sl@0: sl@0: Test.Next(_L("Query play formats supported")); sl@0: TSoundFormatsSupportedV02Buf capsBuf; sl@0: snddev.Caps(capsBuf); sl@0: TSoundFormatsSupportedV02& caps=capsBuf(); sl@0: PrintCaps(caps,Test); sl@0: sl@0: Test.Next(_L("Try playing without setting the buffer config")); sl@0: TRequestStatus pStat; sl@0: snddev.PlayData(pStat,0,0x2000); // 8K sl@0: User::WaitForRequest(pStat); sl@0: Test(pStat.Int()==KErrNotReady); sl@0: sl@0: Test.Next(_L("Configure the channel from a 2nd thread")); sl@0: RThread thread; sl@0: TRequestStatus tStat; sl@0: SSecondaryThreadInfo sti; sl@0: sl@0: sti.iTestId=ESecThreadConfigPlayback; sl@0: sti.iThreadId=RThread().Id(); // Get the ID of this thread sl@0: sti.iDrvHandle=snddev.Handle(); // Pass the channel handle sl@0: sl@0: /** @SYMTestCaseID PBASE-T_SOUNDMCHAN-225 sl@0: @SYMTestCaseDesc Opening the channel - sharing the handle between threads sl@0: @SYMTestPriority Critical sl@0: @SYMTestActions 1) With the LDD and PDD installed and with all channels closed on the device, open a sl@0: channel for playback on the device. Now create a second thread. Resume this sl@0: thread - passing the handle to the playback channel to it. Wait for the second sl@0: thread to terminate. sl@0: 2) In the second thread, duplicate the playback channel handle. sl@0: 3) In the second thread, using the duplicated handle, issue a request to set the audio configuration. sl@0: 4) In the second thread, using the duplicated handle, issue a request to set the volume. sl@0: 5) In the second thread, close the handle and exit the thread. sl@0: 6) In the first thread, read back the audio configuration. sl@0: 7) In the first thread, set the buffer configuration, and then issue a request to play sl@0: audio data. sl@0: 8) In the first thread, close the channel. sl@0: @SYMTestExpectedResults 1) KErrNone - Channel opens successfully. sl@0: 2) KErrNone - Duplication of the handle succeeds. sl@0: 3) KErrNone - Audio configured successfully. sl@0: 4) KErrNone - Volume set successfully. sl@0: 5) No errors occur closing the channel and exiting the thread. sl@0: 6) The audio configuration should correspond to that set by the second thread. sl@0: 7) KErrNone - Setting the buffer configuration and issuing a play request. sl@0: 8) No errors occur closing the channel. sl@0: @SYMREQ PREQ1073.4 */ sl@0: sl@0: r=thread.Create(_L("Thread"),secondaryThread,KDefaultStackSize,KHeapSize,KHeapSize,&sti); // Create secondary thread sl@0: Test(r==KErrNone); sl@0: thread.Logon(tStat); sl@0: thread.Resume(); sl@0: User::WaitForRequest(tStat); sl@0: Test(tStat.Int()==KErrNone); sl@0: // Test.Printf(_L("Thread exit info: Cat:%S, Reason:%x, Type:%d\r\n"),&thread.ExitCategory(),thread.ExitReason(),thread.ExitType()); sl@0: Test(thread.ExitType()==EExitKill); sl@0: thread.Close(); sl@0: User::After(10000); // Wait 10ms sl@0: sl@0: Test.Next(_L("Read back the play configuration")); sl@0: TCurrentSoundFormatV02Buf formatBuf; sl@0: snddev.AudioFormat(formatBuf); sl@0: TCurrentSoundFormatV02& format=formatBuf(); sl@0: PrintConfig(format,Test); sl@0: sl@0: Test.Next(_L("Set the buffer configuration")); sl@0: RChunk chunk; sl@0: TInt bufSize=BytesPerSecond(formatBuf()); // Large enough to hold 1 second of data. sl@0: bufSize=ValidBufferSize(bufSize,caps.iRequestMinSize,formatBuf()); // Keep the buffer length valid for driver. sl@0: TTestSharedChunkBufConfig bufferConfig; sl@0: bufferConfig.iNumBuffers=1; sl@0: bufferConfig.iBufferSizeInBytes=bufSize; sl@0: bufferConfig.iFlags=0; sl@0: TPckg bufferConfigBuf(bufferConfig); sl@0: r=snddev.SetBufferChunkCreate(bufferConfigBuf,chunk); sl@0: Test(r==KErrNone); sl@0: snddev.GetBufferConfig(bufferConfigBuf); sl@0: PrintBufferConf(bufferConfig,Test); sl@0: Test(bufferConfig.iBufferSizeInBytes==bufSize); sl@0: sl@0: Test.Next(_L("Start playing")); sl@0: r=MakeSineTable(format); sl@0: Test(r==KErrNone); sl@0: r=SetToneFrequency(660,format); sl@0: Test(r==KErrNone); sl@0: TPtr8 ptr(chunk.Base()+bufferConfig.iBufferOffsetList[0],bufSize); sl@0: WriteTone(ptr,format); sl@0: snddev.PlayData(pStat,bufferConfig.iBufferOffsetList[0],bufSize,KSndFlagLastSample); sl@0: User::WaitForRequest(pStat); sl@0: Test(tStat.Int()==KErrNone); sl@0: sl@0: Test.Next(_L("Close the drivers and the chunk")); sl@0: chunk.Close(); sl@0: snddev.Close(); sl@0: sl@0: __KHEAP_MARKEND; sl@0: sl@0: Test.Next(_L("Unload the drivers")); sl@0: sl@0: r=User::FreeLogicalDevice(KDevSoundScName); sl@0: Test.Printf(_L("Unloading %S.LDD - %d\r\n"),&KDevSoundScName,r); sl@0: Test(r==KErrNone); 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: Test(r==KErrNone); 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: Test.End(); sl@0: Test.Close(); sl@0: sl@0: Cleanup(); sl@0: sl@0: __UHEAP_MARKEND; sl@0: sl@0: return(KErrNone); sl@0: }