symba (779893), страница 29
Текст из файла (страница 29)
This functionality is provided by CMdaAudioToneUtility.9 Although the same class is used, the calling sequences differ andcan be dealt with separately.CMdaAudioToneUtility shares many characteristics with CMdaAudioOutputStream – it acts as a relatively thin layer over DevSoundand neither runs in a separate thread nor uses a controller object.Nevertheless there are differences: rather than supplying data in buffers,virtually everything is supplied as parameters to the associated play calls.These are, in turn, passed to the underlying DevSound layer, so that thetraffic between the client application and the underlying audio-adaptationlayer is much reduced – compared to the audio output stream scenarios,at least.
One of the reasons for this is that you can supply the parametersfairly succinctly: for example, 100 Hz tone for two seconds can be stated9 To use CMdaAudioToneUtility, include MdaAudioTonePlayer.h and linkagainst mediaclientaudio.lib.130MULTIMEDIA FRAMEWORK: AUDIOin several words – similarly DTMF tone requests can be given as a stringof digits. Even tone sequences are typically more compact than normalaudio formats, and internally whole descriptors’ worth of data are passeddown to the adaptation, instead of on a buffer-by-buffer case.5.6.1 Playing Dual-Tone Multiple Frequency SignalsDual-Tone Multiple Frequency (DTMF) is a standard set of tone signalstraditionally used for ‘digital dialing’ on analog phone systems.
You canobviously use it for other purposes, if you wish. Given its original usage,the DTMF function can handle the keys of a normal phone keypad (0–9,* and #). Additionally ‘A-F’ are defined: E and F are synonymous with *and #, respectively, while A–D have special uses and are not commonlyused. If you really want to know about the interpretation of these, trytyping ‘DTMF’ into a search engine – it will give you all you want toknow and probably a lot more!Early use cases for this code included playing phone numbers asDTMF down a phone line; for that reason, a few additional charactersare supported: spaces are ignored and ‘,’ is treated as a pause.
However,there is no support for the additional characters you often get in phonenumbers, such as ‘() /-’. This use case is largely deprecated, but if youever do want to render phone numbers as DTMF, do take care – you mayhave to strip some extra characters.Playing DTMF strings using CMdaAudioToneUtility is very simple.You set some properties, such as volume and tone lengths to use, andtell it to play the strings.
As with other multimedia APIs, there is slightcomplexity to do with the asynchronous nature of the calls, but this is notparticularly major. Perhaps it is best just to look at an example. This isvery similar to the other examples in this chapter and we won’t look atall the code. The ConstructL() is shown as:void CDtmfSeq::ConstructL(){iToneUtility = CMdaAudioToneUtility::NewL(*this);}There are some additional optional parameters to the NewL() call, butthey are not usually required.Starting play of DTMF looks like:_LIT(KExampleDtmf, &123456789");void CDtmfSeq::Start(){ASSERT(iState == EStateIdle); // calling code must wait for callbackiToneUtility->PrepareToPlayDTMFString(KExampleDtmf);TONE UTILITY131iState = EStatePreparing;}The sequence is a bit different to the other APIs, but in general thereis a Prepare. .
.() call and in return you get a callback to MatoPrepareComplete() to state that this ‘preparation’ phase is complete.This specific example handles the various callbacks as a central Fsm()call:void CDtmfSeq::MatoPrepareComplete(TInt aError){Fsm(EEventPrepared, aError);}void CDtmfSeq::Fsm(TEvent aEvent, TInt aError){TInt error = aError;if (error == KErrNone){switch (iState){case EStatePreparing:{ASSERT(aEvent == EEventPrepared); // nothing else expected// set volume to 3/4 of the maximum volumeiToneUtility->SetVolume(3*iToneUtility->MaxVolume()/4);iToneUtility->Play();iState = EStatePlaying;}break;case EStatePlaying:{ASSERT(aEvent==EEventPlayed); // nothing else expected// normal completioniState = EStateIdle;iObserver->SequenceComplete(KErrNone);}break;}}if (error != KErrNone){Cancel();iState = EStateIdle;iObserver->SequenceComplete(error);}}On preparing, this sets the volume to three-quarters of MaxVolume()and then calls Play().
On any errors, the system ‘cancels’ beforereturning an error callback. This cancel operation is quite important:132MULTIMEDIA FRAMEWORK: AUDIOvoid CDtmfSeq::Cancel(){switch (iState){case EStateIdle:// do nothingbreak;case EStatePreparing:{iToneUtility->CancelPrepare();}break;case EStatePlaying:{iToneUtility->CancelPlay();}break;}}There is no single ‘Stop’ call and it’s probably better to be carefulabout what you cancel.On termination of play, you get a MatoPlayComplete() callback,which in this example is fed back the same way.void CDtmfSeq::MatoPlayComplete(TInt aError){Fsm(EEventPlayed, aError);}For security reasons, it is worth being careful what you play. Ifit can be heard by anyone other than the end user, it is possible for someone to hear and transcribe the number or to recordit automatically.
If you are just using it for an effect, then perhapsensuring the DTMF string is not the real string might be a goodidea – in the same way, ATMs now tend to play the same tone foreach key.Note: DTMF data is given as 16-bit descriptors, reflecting that itprobably originates as a phone number and is human-readable ratherthan binary.5.6.2 Playing Tones‘Tones’ in this context are pure sine waves – well, as pure as can beachieved. Dual tones are two sine waves mixed together. The calls arepretty simple to use – apart from ensuring the volume, etc. is correct, youjust give the frequencies to generate and the time to play, then the systemdoes the rest. The use is very similar to the DTMF example, apart fromhow you specify what to play.
Key to the implementation are two calls:TONE UTILITY133void PrepareToPlayTone(TInt aFrequency,const TTimeIntervalMicroSeconds& aDuration);void PrepareToPlayDualTone(TInt aFrequencyOne, TInt aFrequencyTwo,const TTimeIntervalMicroSeconds& aDuration);As before, these don’t actually make any sound, but they set up thetone utility so that a subsequent Play() call makes the correct sound.You call Play() once you receive the MatoPrepareComplete()callback.You might want to abandon the tone play before it has got to the end,for example, because the application cancels an associated screen view.To do this, make a call from your API that implements something like theCancel() call given in Section 5.6.1.5.6.3 Playing Tone SequencesPlaying a tone sequence is akin to playing an audio file (see Section 5.3)but sequence files are inherently simpler.
Not only is no controllerrequired but the sequence is decoded in the adaptation layer. Althoughthe use case is similar to that of playing audio files, the calling pattern issimilar to that of playing DTMF or tones.There are several ways of playing a tone sequence:• provide the tone sequence in a descriptor• provide a filename that contains the tone sequence data• use RFile::Open() to open a file that contains the tone sequence• play a fixed sequence by index.Internally there is not that much difference between them – the CMdaAudioToneUtility implementation reads the file contents into adescriptor and plays that – but that is internal and not really observable to the client.
If you have a file, then generally we recommendusing the RFile approach as it is easier to change your code to supportfiles passed from other applications. However, in most situations thedifferences are minor.Code would be similar to the DTMF example, but using differentPrepare. . . calls:void PrepareToPlayDesSequence(const TDesC8& aSequence);void PrepareToPlayFileSequence(const TDesC& aFileName);void PrepareToPlayFileSequence(RFile& aFile);The two PrepareToPlayFileSequence() calls play a file whengiven either a filename or an RFile object. PrepareToPlayDes-134MULTIMEDIA FRAMEWORK: AUDIOSequence() effectively expects the contents of a file.
Playing a fixedsequence is a bit different. They are built into the audio adaptation andare accessed by index. The following call plays a sequence:void PrepareToPlayFixedSequence(TInt aSequenceNumber);The following method tells you how many fixed sequences are provided on a given device:TInt FixedSequenceCount();The following method tells you the name of the associated sequence:const TDesC& FixedSequenceName(TInt aSequenceNumber);A key scenario is to read the names into a CDesCArray object, usinga for loop, which can then be used as part of a selection box.Apart from that, this API is similar in form to playing from a file.However, it is not always implemented.
If it is not implemented, FixedSequenceCount() returns 0. If you do use these calls, take care toensure that the behavior is valid if FixedSequenceCount() returns0 – be careful of using choice lists with no content. Remember that thefollowing call does not reliably play a sound:PrepareToPlayFixedSequence(0);If you do just want to make a sound, then playing simple tones isprobably more reliable.5.7 DevSoundDevSound (properly CMMFDevSound) is the fundamental component atthe bottom of the MMF API stack. It encapsulates the audio adaptationsfor devices. Under DevSound are found the lower-level audio codecs,the audio policy (what happens if more than one client requests to playor record concurrently) and the links to the various audio devices. Thesefeatures are common to all the DevSound implementations on differentSymbian smartphones, but the underlying architecture varies from onemanufacturer to another, and even from one model to another.Details of how to use CMMFDevSound are not described furtherhere – the headers, libraries and documentation for the class is notAUDIO POLICIES135included in every SDK, and in many situations the API differs fromthat generally convenient for application programmers.