The BREW Bag Of Tricks

The BREW Bag Of Tricks
How to deal with inconsistencies and
firmware bugs in BREW phones during
game development
by
Guido Henkel, CEO
[email protected]
G3 Studios – http://www.g3studios.com
Game Developers Conference 2005
1
Introduction
Over the past year or two the half-life of a BREW
handset has shrunk from somewhere around 1
year to about 4 months. That means any handset
coming to market now is bound to be outdated
and off the shelves in about 8 – 10 months
At the same time carriers like Verizon Wireless are
adding new handsets to their line-up at a heartstopping pace. The pressure to create and bring
new handsets to market in ever shorter amounts
of time is enormous
As a result handsets that had insufficient testing
and are riddled with firmware bugs have become
the frightening reality of BREW development
Game Developers Conference 2005
2
Introduction
It is impossible to cover all problem areas
you may encounter while developing
BREW applications, so the examples I
will give here are really just random
samples that I have encountered and
dealt with
Game Developers Conference 2005
3
Pearl Of Wisdom
Use as little of the BREW API
as possible!
Game Developers Conference 2005
4
Pearl Of Wisdom
The less you rely on the BREW implementation the less you will be subject to
firmware bugs and software issues. Create your own framework and
implement most of the functionality yourself. That way you have full control
over it and you can make sure the implementation is properly running on
any handset
In my BREW games, I usually use only a handful of of BREW API calls, such as
IFILE – to read and write data including BAR files
ISOUNDPLAYER – for sound output
IHEAP – only selected functions for my own memory handler
IBITMAP – only selected functions to obtain IDIB and native color info
IDISPLAY_UpdateEx() – to render the framebuffer
ISHELL_SetTimer()
ISHELL_CloseApp()
ISHELL_CreateInstance()
Everything else I implement manually, including things such as the STDIO
helper functions – strcpy(), memcpy(), atoi() etc.
Game Developers Conference 2005
5
The Font Front
Menuing, text output and text input are broken on a large number of
handsets
They also do not give you any control over the screen layout since
fonts, kerning, line spacing and visual presentation vary from
handset to handset. The ISTATIC API in particular is completely
broken on various handsets, including the Samsung A610 and LG
vx6000, and occasionally carriers won’t even accept applications
that make use of the ISTATIC API on those handsets
To solve this problem and to avoid the firmware bugs in these APIs I
recommend writing your own text output and menuing classes.
These are very easy to do and give you a consistent look across
handsets. They are predictable and expandable and you can
make them as simple or as elaborate as you need them
Game Developers Conference 2005
6
Pixels Of Doom
Although most handsets have a 16-bit color display model, the
introduction of the Motorola v710 introduced a new set of problems. It
is using an 18-bit color depth, represented as a 32-bit RGB888 model
Using a dedicated datatype for all pixel operations solves the problem
very quickly and without any code changes
For 16-bit displays, simply define your pixel like this
typedef unsigned short
mypixel;
While for 32-bit displays you could define it like such
typedef unsigned int
mypixel;
If you consistently use your custom pixel data type to do all display
related operations the compiler will automatically create the proper
memory layout for you. All it takes is a simple re-compile
Game Developers Conference 2005
7
Kyocera vs. The Bitmaps
Kyocera BREW phones have a firmware bug that propagates through
ALL their models. From the KX414 all the way to the KX2
Their phones allocate twice the amount of memory that is actually
needed when you make calls to CONVERTBMP() or
IBITMAP_CreateCompatibleBitmap(), quickly eating away your
precious and all-too-sparse memory resources
Depending on which SDK version you are developing for, there are
ways to get around this
Game Developers Conference 2005
8
Kyocera vs. The Bitmaps
In BREW 1.1 it requires you to essentially hack into the native
bitmap format of the handset and write your own CONVERTBMP()
implementation which allocates the proper amount of memory. I
do have a replacement module of CONVERTBMP() for these phones
that I am licensing for a nominal fee
In BREW 2.0 it is much easier as you have access to the handset’s
native bitmap format through the documented IDIBs. Here you
can easily write an own implementation of
IBITMAP_CreateCompatibleBitmap() to solve the problem since
all the function is doing is creating an IBITMAP/IDIB object and
associating it with memory to hold the bitmap
Game Developers Conference 2005
9
The Sound Of Music
There are a few notable issues associated with the ISOUNDPLAYER
API on a variety of phones. While some of them are easily fixed
or avoided, others are sadly complete show stoppers
Samsung handsets for example are unable to pause and resume
MIDI tracks. A call to ISOUNDPLAYER_Resume() is simply ignored
and silence will prevail. What’s even worse is that a call to
ISOUNDPLAYER_Pause() will not do anything either. The audio will
continue to play, wreaking havoc on incoming calls. This problem
can also be found on a variety of other handset
A solution to this problem is to simply use ISOUNDPLAYER_Start()
and ISOUNDPLAYER_Stop() in their stead. While you can do that
selectively only on handsets exhibiting the problem I found it
much safer to completely remove ISOUNDPLAYER_Pause() and
ISOUNDPLAYER_Resume() from my code base
Game Developers Conference 2005
10
The Sound Of Music
If you use the ISOUNDPLAYER API to also play back MIDI sound
effects, you may have noticed that on a number of handsets
restarting a sound effect will create a clearly audible
popping/cracking sound, especially when you have some rapidfire sound effects being played back consistently
This is a timing problem inherent in the audio architecture of each
handset. To avoid the cracking sound simply create a moment of
silence before starting a new MIDI effect. I do this using a short
delay timer that keeps the API idle for a variable amount of time.
This delay ranges anywhere from 0ms on some handsets all the
way to 300ms on the vx4400
Game Developers Conference 2005
11
The Sound Of Music
Many Nokia phones have also serious issues with the ISOUNDPLAYER
API resulting in most games for these handsets being mute. One
of the issues is that it is impossible to loop MIDI tracks using the
API
The firmware of these phones has a bug that consistently shoots
messages to BREW and your application, indicating that it has
completed playing back a MIDI track, even though it has just yet
started. These rapid-fire events will stall the handset and in many
cases cause it to actually reset if they cannot be processed fast
enough by your application
I have been working with Nokia to isolate the problem and
fortunately it has been fixed in the latest handsets, such as the
6255i. On all earlier phones however there is no work-around
available to the best of my knowledge
Game Developers Conference 2005
12
The Sound Of Music
On top of these API errors a large number of handsets do not
properly report the volume keys to the operating system. As a
result, sadly, on these handsets it is impossible to actually adjust
the volume unless you will do it programmatically with a useradjustable slider
To make matters worse, some of these handsets in particular are
playing back sounds at a deafening volume. In these cases it may
be necessary to adjust the volume programmatically
Game Developers Conference 2005
13
The Sound Of Music
Even if you handle audio volume from within your application you will
find that some handsets simply ignore the
ISOUNDPLAYER_SetVolume() command. On the vx4400 and t720,
for example it is impossible to adjust the volume at all
On other handsets you may find adjusting the volume does work but
has unwanted side effects, such as affecting the phone’s user
settings, so make sure to use the ISOUNDPLAYER API with a bit
of suspicion at all times
Game Developers Conference 2005
14
Memoirs of the Invisible
Memory
Despite its many strengths, the Audiovox CDM-8900 can be quite a
challenge for game developers. With a display of 128x146 pixels
it requires a bit of memory to do back buffering, soft scrolling etc
on this handset.
Unfortunately despite it being listed as having 500kB of RAM, the
handset offers up much less for BREW applications and you will
find that you actually have only about 440kB at your disposal on
this handset
In order to make more room on this handset I reverted to a simple
trick
Game Developers Conference 2005
15
Memoirs of the Invisible
Memory
After doing some research I noticed that the handset
allocates a significant, permanent buffer of about 12kB
the first time you access your BAR file. This is done in
order to buffer the directory structure of the BAR file I
presume and to buffer the input stream
By replacing BREW’s ISHELL_LoadResData() function with
my own implementation I was able to reduce this
memory footprint to 1kB
Additionally, working with bitmaps in palettized 8-bit format
as opposed to fully expanded native 16-bit can
sometimes be very useful, especially if the image is not
rendered very frequently. There is a significant
performance hit for a blitter-routine that does on-the-fly
8-to-16bit conversion because of the cache thrashing, but
if you really need to save some memory, this is one way
to go about it
Game Developers Conference 2005
16
Memoirs of the Invisible
Memory
The Audiovox CDM-9900 has a large display with 240x292 pixels.
The problem with this phone is that there is insufficient heap
memory to do anything sensible with it
The handset is listed as having a meager 640kB of RAM which is
ridiculous considering that the display itself takes up about
140kB. Whatever you do you will always be severely strapped for
memory on this handset and the only way I was able to alleviate
this was by rendering my apps into a 120x146 pixel backbuffer
and then scaling it up in real time just in time before the display
refresh
Game Developers Conference 2005
17
Stay With Me
There is a major issue with the IWEB interface that is not documented. If
you pass a URL to the API that is located in the local scope, IWEB calls
will fail because the variable doesn’t stay around long enough for the
respective callback calls inside the OS. URLs have to be global to the
application in scope!
This version does not work…
void
ReadFromServer( applet *curApp, const G3string *fileName )
{
G3string buffer[128];
StringCopy( buffer, (G3string *)"http://www.somedomain.com" );
StringCat( buffer, fileName );
curApp->ConnectionStatus
= CONNECTION_IDLE;
G3_DESTROY_ARRAY( curApp->ConnectionBuffer ) // Free existing connection buffer
IWEB_GetResponse( curApp->HTTP, ( curApp->HTTP, &curApp->HTTPResponse, &curApp>Callback, (const char *) curApp->Scratch, WEBOPT_END ) );
}
Replacing buffer[] with a global instance in the applet scope will fix things
Game Developers Conference 2005
18
I Saw What You Did
When writing your own blitter routines make sure to always, always
properly clip your blits. Do not rely on the handset to do any
clipping for you
Handsets like the t720 and vx4400 among others have firmware bugs
that cause the handset to crash in this area if you attempt to blit to
negative x-coordinates or to a coordinate outside the physical
display area. Clipping is trivial, takes only a few lines of code and
should be part of every industrial strength blitter routine
Here’s a brief example for clipping x-coordinates
if ( xPos < Clip.left )
{
width += xPos - Clip.left;
xSrc -= xPos - Clip.left;
xPos
= Clip.left;
}
if ( ( xPos + width ) > ( Clip.left + Clip.right ) )
{
width = width - ( xPos + width - ( Clip.left + Clip.right ) );
}
Game Developers Conference 2005
19
Coffee Is For Closers
With the BREW 2.0 SDK Qualcomm introduced the concept of IDIBs,
which give programmers direct access to the native bitmap data of
a handset. Sadly however, IDIBs are not supported by all handsets.
The Audiovox CDM-9900 as well as Kyocera’s KX1 and KX2
handsets, for example, do not allow applications to retrieve the
IDIB interface of a bitmap
Fortunately there is a work-around. An IDIB is in reality nothing more
than a public interface for BREW’s IBITMAP object. It has no actual
functionality and only exposes the contents of the IBITMAP object
to the application. With that in mind an IDIB interface can simply be
created using a static cast that looks something like this
IBITMAP_QueryInterface( imgBuffer, AEECLSID_DIB, (void **) &imgPixels );
if ( NULL == imgPixels )
{
imgPixels = (IDIB *)imgBuffer;
}
Game Developers Conference 2005
// If device doesn't support
// the IDIB API, simulate it!
20
I See You, Now I Don’t
The concept of dirty rectangles has been a valuable part of BREW’s
display update routines particularly on lower end phones. With the
introduction of BREW 2.0’s IDIBs and the direct memory access
they provide, dirty rectangle algorithms can quickly become traps
on handsets such as the LG vx6000, LG vx7000 or the CDM-9900
Due to firmware bugs these handsets do not properly recognize when
an application is directly writing to the display’s frame buffer. As a
result the dirty rectangle algorithm oftentimes prevents the display
from doing a proper redraw
You can use a few simple lines of code to force the handset to mark the
entire screen dirty. Simply draw a pixel in the upper left and one in
the lower right corner of the screen using a BREW API call
NativeColor color = IBITMAP_RGBToNative(DeviceBitmap, MAKE_RGB( 0, 0, 0 ));
IBITMAP_DrawPixel( curApp->DeviceBitmap, 0, 0, color, AEE_RO_XOR );
IBITMAP_DrawPixel( curApp->DeviceBitmap, 239, 291, color, AEE_RO_XOR );
Game Developers Conference 2005
21
Faster, Pussycat!
If you have an application that is fairly processing-intensive you may notice that on lower end
handsets key presses are delayed and not immediately reported
In order to avoid this problem I give the OS more time to breathe by staggering execution of
program parts. The application is doubling the event timer frequency to relinquish control to
BREW more often and then flip-flops between executing game play and rendering code. I
found that it dramatically increased the overall responsiveness of the handsets in question
void
GameEvent( applet *curApp )
{
if ( 0 == curApp->FlipFlop )
{
curApp->sasApp->run();
if ( 0 == curApp->DevCfg->FlipFlop )
{
IDISPLAY_UpdateEx( curApp->a.m_pIDisplay, FALSE );
}
else
{
curApp->FlipFlop++;
}
}
else
{
curApp->FlipFlop = 0;
IDISPLAY_UpdateEx( curApp->a.m_pIDisplay, FALSE );
}
Game
} Developers Conference 2005
//
//
//
//
//
On some handsets we need to
speed up the event timer in
order to improve
responsiveness and to satisfy
the watch dog
22
Call Me
A strange problem I once had on a few handsets was that incoming
calls and SMS messages were simply ignored by the phone while
my game was active. Interestingly the behavior was limited to
particular screens within the application
Some research into this showed that as in the previous example my
application was simply eating up too much processing power,
making it impossible for BREW to handle the incoming call.
Lightening the work and rendering load in those screens in question
solved the problem
While the solution was simple it also shows that it is every important
for you to test incoming calls and SMS in every screen you may
have in your game, as each of them generates a unique load on the
processor
Game Developers Conference 2005
23
Maniac Cop
A few Samsung phones are notorious for watch dog timer issues, in
particular the a530 handset. The watch dog may kick in terminating
your application despite the fact that there is nothing wrong with
your application or the processing time it consumes
There is a very simple solution to this problem which I found works in
99% of all cases. When you render your display, instead of using
IDISPLAY_Update() use the function IDISPLAY_UpdateEx()
instead and the watch dog will lie sleeping as it should
IDISPLAY_UpdateEx() is recommendable on all phones, by the way, as
it gives you more control over the rendering timing and thus
ensures steadier frame rates
Game Developers Conference 2005
24
Topsy-Turvy
Some of the Nokia phones use big endian datatypes as opposed to little
endian data that are used on most other BREW phones. While
normally this isn’t a problem at all, it can become an issue if you
are loading binary data from a file that has been prepared for little
endianess
Two small routines – one for 16 bit integers and one for 32-bit integers
– can be used to change the endianess on the fly thus making it
possible to use the same data sets for big and little endian
platforms without change
short
SwapEndian( register short inVal )
{
return ( ( inVal & 0xFF ) << 8 ) | ( ( inVal & 0xFF00 ) >> 8 );
}
The endianess of a platform can be determined at runtime by writing
an integer to memory and reading it back bytewise, checking the
order in which the data bytes have been committed to memory
Game Developers Conference 2005
25
The Good, The Bad And
The Ugly
Vibration is the Stygian Abyss of BREW handsets. It is unusable on
virtually all handsets for a wide variety of reasons. While the BREW
API allows you to define a vibration duration, the t720 for example
ignores the parameter and will always vibrate three times in a row.
Other handsets override the duration parameter and vibrate for an
undefined period of time. Other handsets yet will stop all audio
output as soon as they start vibrating or whatnot.
The Audiovox CDM-8900 takes the cake in the vibrator-department
however. It allows you to start vibration but there is no way
stopping it. Not even powering it down will work. The handset will
vibrate until the battery is removed.
My recommendation - forget about vibration in BREW applications!
Game Developers Conference 2005
26
One MIF Fits All
MIF file settings are oftentimes a mystery to BREW developers,
including the proper image sizes to include. Documentation on this
end is spotty at best and also changes across carriers
To create a MIF file that works for every handset, I always make sure
my MIF file is edited and saved in the BREW 1.1 format. Since Brew
is backward compatible this MIF format can be read on any handset
and you can use this MIF file for each and every handset
Regardless of what Device Data Sheets specify, I always use the same
image sizes for the images to include. I use 26x26 pixel icons for
the “Icon” and “Image” entry and a 16x16 pixel icon for the
“Thumbnail” entry. Since no handset is making actual use of the
large “Image” file, I am sticking with the bare minimum image sizes
of all handsets and therefore am able to use such a MIF file for each
and every handset
Game Developers Conference 2005
27
License To Kill
Also in regards to MIF files, a peculiar problem has surfaced on the LG
vx6000 regarding licensing types. Occasionally you may want to
adjust your demo mode of the game by using the PT_DEMO and
PT_PURCHASE license types to see if the game has been purchased
or not. On the vx6000 you have to be careful creating the MIF file
that determines this setting
Always make sure to create MIF files that contain licensing information
using the 2.x MIF editors, saving the MIF file as 2.0 versions. If you
save the MIF file as a 1.1 version the licensing information is
corrupted and the application will be perpetually running in an
unlimited mode. You are essentially giving away your game for free
if it is provisioned that way on a carrier’s server!
Game Developers Conference 2005
28
The Name Of The Rose
Naming your application is key to its success. Since there is no
presentation platform in BREW and users have to decide whether
they are interested in a game or not solely by its name, choosing
the right name is crucial
It is possible to choose a name that is too long. Although there is no
documentation on the subject and neither NSTL nor Qualcomm
were able to provide me with accurate information, it seems that a
length of 24 characters for an application name is the hard limit.
Anything beyond that is exceedingly dangerous and freaks out
various handsets. As a result the application will be be cancelled or
may even fail True Brew Testing
Limit your application names to 24 characters to be on the safe side!
Game Developers Conference 2005
29
Roll Over, Lay Down
On BREW 2.x handsets you may occasionally experience a strange behavior. When pressing the
“CLR” key to terminate the application you may find that instead of returning to the phone’s
BREW screen it actually launches the BREW shop. This behavior will cause your application
to fail True Brew Testing so it needs to be addressed
The solution is usually very simple. Make sure to handle your CLR key events in the EVT_KEY
handler as opposed to the EVT_KEYPRESSED handler and the problem will go away
However, do not handle all key events in the EVT_KEY handler, as some handsets require you
handle them in the EVT_KEYPRESSED handler. Something like this works on all handsets…
case EVT_KEY_PRESS:
if ( AVK_CLR != wParam )
{
keyPressed( curApp, wParam );
}
retFlag = TRUE;
break;
case EVT_KEY:
if ( AVK_CLR == wParam )
{
keyPressed( curApp, wParam );
}
retFlag = TRUE;
break;
Game Developers Conference 2005
30
Deadwood
Connecting a handset to the PC and getting applications loaded using
AppLoader can be a taunting nightmare. With so many handsets
and USB cables your system will eventually run out of assignable
USB ports and Qualcomm’s tools typically recognize only a small
subset of these ports, making matters even worse. Add to that the
nightmare of obtaining the correct drivers, rebooting your computer
and handset countless times, and the driver collisions coming along
with installing drivers for some 50 handsets and you’re soon
reduced to a drivel
One thing that has saved my sanity on many occasions in that respect
is a SERIAL cable for the vx6000. The vx6000 communications port
can almost be viewed as an industry standard and I know of at least
15-20 handsets from various manufacturers that you can use the
vx6000 cable with without a hitch. It always connects – much faster
than the USB counterpart – and best of all, it does not require a
driver! It just works!
Game Developers Conference 2005
31
Let Sleeping Corpses Lie
One area of constant trouble as a BREW Developer are the emulator
skins provided to developers by Qualcomm through their Extranet.
Every developer I know has at one point or another stared at his
application on the screen in disbelief, wondering what happened to
his code that causes the application to create a completely garbled
screen output
In most cases it turns out that the emulator skin contains incorrect
settings, such as incorrect parameters for display window
dimensions, the display resolution, the color depth, the device ID or
the memory settings.
Therefore, before using an emulator skin for the first time, doublecheck its settings using the Device Configurator and set it up
according to the information on the Device Data Sheet. Since the
emulator doesn’t really emulate anything beyond these five skin
settings these parameters are absolutely crucial
Game Developers Conference 2005
32
Under A Glass Moon Sky
In retrospect many of the issues I just discussed could have been
avoided. In an ideal world I would wish that Qualcomm, OEMs and
carriers would take a few steps to help minimizing such problems in
the future. In order to achieve that, they should
• Involve developers in pre-release certification and encourage
their input
• Openly document some of the data formats in use, such as the
MIF and BAR formats to allow developers to write streamlined
tools of their own
• Create accountability in conforming with the BREW API so that
it becomes everyone’s best interest to create BREW
implementations that are fully functional
Game Developers Conference 2005
33
Thank You!
I would love to hear your ideas and tips
from your own bag of tricks
You can always contact me at
[email protected]
Game Developers Conference 2005
34