Wiley.Games.on.Symbian.OS.A.Handbook.for.Mobile.Development.Apr.2008 (779888), страница 31
Текст из файла (страница 31)
A multimedia policy component is responsible formaking the decisions based on rules implemented in it. Each licenseemight have a different set of system and multimedia applications, so theyset their own set of rules.The one rule that is important for game developers is that games arenot system critical, so they will always have lower priority than othersystem applications. There is always the possibility that audio requestsmade by the game might return KErrInUse (or KErrAccessDenied insome devices), or a system application might preempt any playing audioto play an alarm sound or a ringtone.It is important to program any audio engine considering this fact.Handling error cases properly is a good software engineering practicefor any kind of application.
In addition to that, there are asynchronousnotifications that you can register to be informed when an unavailableresource becomes available.The following sections will examine the different interfaces and APIs ofthe MMF useful for game development in further detail. The examples will128ADDING AUDIO TO GAMES ON SYMBIAN OSbe using the Symbian PCM codec (WAV format), because Symbian supplies this codec so that any phone model based on Symbian OS willsupport it.4.3 Sound EffectsThe most important audio task that a mobile game needs to implement issound effects. These complement the visual feedback the user gets fromthe screen by providing real-time audio cues about the action going on inthe game. Because of the small screen sizes, having good sound effectsis even more important on a mobile device. A good explosion effect willhave a bigger emotional impact on the player than a tiny animation onthe small screen.One of the major problems with supporting quality sound effects onmobile devices is the memory limitation.
Good quality sound effects takeup much space on the flash drive and in memory. However, with thelatest advances in the storage capacities of Symbian OS devices and theincreasing number of hardware accelerated compressed audio codecs,memory consumption is less of a problem nowadays.The other remaining problem with sound effects is latency. Mobiledevices have limited processing power, and non-essential audio tasks(tasks not related to the operation of phone functionality) in general arenot high-priority tasks. The generation of real-time sound effects becomesvery challenging unless developers give special attention to the creationof the audio engines.In Symbian OS, multiple audio APIs give the user different levels ofcontrol over the audio system.
In order to create sound effects in SymbianOS, an application can use the MMF client API or can use the DevSoundinterface to access the audio hardware directly. The MMF client API iseasier and more straightforward to use, but control over the hardware islimited and some operations like audio streaming have a performancepenalty caused by an extra layer of buffering in the framework.
DevSoundis the lowest level audio API available on Symbian OS. It is more powerful,but requires more knowledge of the native audio support provided bya device.For most casual games, the MMF API will be sufficient for creating simple effects. The CMdaAudioPlayerUtility and CMdaAudioToneUtility classes of the MMF API are used to play single audio clipsor audio tones (fixed or custom non-digitized ringtones).
These classesprovide many methods, but only the functionality useful for generic gamedevelopment tasks are in the scope of this book.4.3.1 Audio Clip PlayerFor most types of games, developers use digitized sound effects storedin sound files in one of the supported formats of the target devices. TheSOUND EFFECTS129installation process transfers these files to the target device together withthe game executable. Once the game starts, the game audio engine willneed to play the effects in response to certain game events.For playing digitized sound clips, Symbian OS provides CMdaAudioPlayerUtility class, defined in MdaAudioSamplePlayer.h. Thisclass provides the functionality to play the audio clip directly from a fileon the device or from a descriptor in memory.In order to use CMdaAudioPlayerUtility, the audio engine shouldimplement the observer mixin class MMdaAudioPlayerCallback.class CAudioDemo : public CActive, MMdaAudioPlayerCallback{public:virtual void MapcInitComplete(TInt aError, constTTimeIntervalMicroSeconds &aDuration);virtual void MapcPlayComplete(TInt aError);private:CMdaAudioPlayerUtility* iPlayerUtil;};When the engine is constructed, it should initialize the player utilityobject by passing itself as the observer.
The priority setting passed inthe second parameter does not have any effect for applications that donot have the MultimediaDD capability. The MMF uses the priority todetermine which applications will have access to the audio hardware ata given time; games as a category have a lower priority than most otherapplications.For games, the last parameter ‘priority preference’ is more important.The default setting is EMdaPriorityPreferenceTimeAndQuality,which fails playback operations if another client with higher priority (forexample, media player) is currently using the audio resource. By usingEMdaPriorityPreferenceTime, it is possible to play the audio clipmixed with the current audio or have the clip audio muted.Of course the real meaning of both of these parameters is interpretedaccording to the audio policy of the device, which is device manufacturerdependent, so the exact behavior will vary from device to device (or atleast from manufacturer to manufacturer).void CAudioDemo::ConstructL(){iPlayerUtil = CMdaAudioPlayerUtility::NewL(*this, EMdaPriorityNormal,EMdaPriorityPreferenceTime);}The OpenFileL() method initializes the player object with theinformation it reads from the file header prior to playing a file.
Thismethod has overloads for a descriptor filename, an open RFile filehandle or a TMMSource-based class for DRM-protected file access.130ADDING AUDIO TO GAMES ON SYMBIAN OSvoid CAudioDemo::OpenClipL(){_LIT(KFile, "z:\\system\\sounds\\digital\\namediallerstarttone.wav");iPlayerUtil->OpenFileL(KFile);...}OpenFileL() is asynchronous and it will complete by callingMapcInitComplete().void CAudioDemo::MapcInitComplete(TInt aError, constTTimeIntervalMicroSeconds& aDuration){if (aError == KErrNone){// File is ready to play}else if (aError == KErrNotSupported){// Codec to play this file is not available on this device}else{// Other errors, handle here}}After the MapcInitComplete() callback returns, the file is ready toplay using the Play() method.void CAudioDemo::PlayClipL(){...iPlayerUtil->Play();}PlayFileL() will play the file asynchronously and it will completeby calling MapcPlayComplete().void CAudioDemo::MapcPlayComplete(TInt aError){if (aError == KErrNone){// File successfully played}else if (aError == KErrCorrupt){// Data in the file is corrupt}else if ((aError == KErrInUse) || (aError == KErrAccessDenied)){// Another higher priority client is using the audio device}SOUND EFFECTS131else if (aError == KErrUnderflow){// System is under heavy load, MMF could not provide the HW// with audio data fast enough.
Best course of action is retryingiPlayerUtil->Play();}else{// Other errors, handle here}}It is possible to pause or stop a clip while playing. Pause() willpause the clip, and when it is paused, calling SetPosition() canchange the current playback position. A play window can be set withSetPlayWindow(), limiting the play command to play only a portionof a clip. Stop() will stop the playing clip, reset the current playbackposition to the start of the play window (or the clip if there’s no playwindow), but does not close the file. Calling Play() will restart playing.However, on certain hardware platforms Pause() is implemented bycalling Stop() and resume will require reinitializing and repositioningas well as a PlayData() call.
You should find out the exact behavioron your chosen target devices and develop your code accordingly.If any play command returns KErrInUse or KErrAccessDenied inMapcPlayComplete, this means the audio resource is not available atthe moment. A Play() command might return this error code immediately, which means the device is in use by another client, of higherpriority.
MapcPlayComplete might also return the error code sometimeafter the clip starts playing normally. In this case, the audio clip startsplaying but, prior to finishing, another higher priority client requests theaudio device and preempts the currently playing audio client.Handling this case properly is important for portability of the gamebecause the behavior of the device in this case is licensee-dependentand the emulators behave differently from the real devices. SymbianOS provides a generic notification mechanism for audio resource availability in the MMF API through the RegisterAudioResourceNotification() method. This method registers an observer to receivenotifications when the audio resources become available.
The observermixin class to implement is MMMFAudioResourceNotificationCallback().class CAudioDemo : public CActive,MMMFAudioResourceNotificationCallback{public:virtual void MarncResourceAvailable(TUid aNotificationEventId, constTDesC8& aNotificationData);};132ADDING AUDIO TO GAMES ON SYMBIAN OSNotification registration is available after the clip starts playing, including inside MatoPlayComplete().iPlayerUtil->Play();...TInt err = iPlayerUtil->RegisterAudioResourceNotification(*this,KMMFEventCategoryAudioResourceAvailable);if ((err != KErrAlreadyExists) && (err != KErrNone)){// Other errors, handle here}If another audio client preempts the playing client, the audio policyserver will notify this client by calling the MarncResourceAvailable() method. The notification data parameter will contain the positionwhere the currently playing clip was interrupted, so the engine can resumethe clip from that position using this data.