Thursday, March 29, 2012

Koi Live Wallpaper v1.35

  - New Feature: Fish startle when touched!
  - Update: Improved performance on Tegra devices

This updates gives us a couple goodies, in particular you can now interact with the fish a notch more than previously.  Tapping on one will now startle it and cause it to swim quickly away for a second or so.

In addition, we have some logic in place now that will optionally clear buffers based on whether or not the current device prefers it.  This means some devices got a pretty substantial improvement -- in particular Tegra chipsets should be a notch smoother than before.

Canabalt HD v1.05

  - New Feature: Localization to french, italian, german, spanish
  - Update: Re-using an existing account better supported
  - Bug Fix: Occasional crash during building generation
  - Bug Fix: Difficult window at building 4

The big thing here is getting localization in place for a few major european languages, and fixing some minor crash issues at the same time.  People seem to be really digging the game so far, so look for more updates in the future.  :)

Please let us know if anything goes amiss!  Look for these fixes on Kindle and Nook devices in the next few days.

Sunday, March 25, 2012

Lines Live Wallpaper v1.0

( Google Play link )

This feels like it needs a cleverer name, but I've been at a loss so am going with the simple one for now.  :)

Lines is an abstract live wallpaper with a collection of lines streaking across your screen.  They move in/out of the scene as you slide the camera, and respond to touch with via vibration and color changes.  The nice thing about this one it it's graphically simple enough to be extremely performant, even on fill-rate starved devices like a Galaxy Nexus.


If you're in the mood for something abstract, give it a shot!

Thursday, March 22, 2012

Canabalt HD on Nook

Took a while to show up in the actual store, but as of this morning Canabalt HD is now available on Nook devices as well!  Click here if you've got a Nook Color or Nook Tablet.  :)

Wednesday, March 21, 2012

Android Sound Playback at 60Hz

Sound effect playback was added to Canabalt HD pretty late in the development cycle. True to form for any late-coming feature, it didn't arrive without one or two terrifying complications. Jeremy already covered one the issues we faced in his post about sound file compatibility. It also turned out that playing the sound effects themselves caused pretty significant hitches in the game. That's the other problem we had to tackle and is what this post is about.

To set the stage, Canabalt is a game that tries to run at sixty updates, or frames, per second (60Hz). That's the fastest rate available on most displays, so it's a common target for driving, shooting, sports, or reflex games like Canabalt. A 60Hz update rate gives us 16.666ms per frame (60 / 1 second = 0.01666s = 16.666ms) to do everything related to running the game: gather input, simulate physics, prepare the scene for rendering, a bunch of other things, and play sounds.

Not long after adding sound effect playback via the SoundPool class, we started to notice the game running kind of rough. The game would visibly stutter on occasion and miss input events, meaning the main character wouldn't jump when you asked him to. Not fun, and certainly not shippable.

The culprit was the call to SoundPool.play(). Seen here in an image from a bare-bones test application that I wrote while diagnosing this problem, the game thread was spending anywhere from 1-9ms(!) just waiting to start playing back a sound. Not pictured are some instances of sounds taking more than 12ms to start (rare, but it happens). That's not only quite volatile, but also way, way over-budget!

To narrow down what was going on, I tried changing every variable that I could think of, one at a time:

* SoundPool is build on top of AudioTrack, which is the lowest-level sound API available to apps written Java. So, the first thing I tried was using AudioTrack directly. Operating in static mode, any combination of AudioTrack calls that would reliably play sound effects properly netted basically the same delay. Streaming mode clocked in at several hundred milliseconds per fill of the streaming buffer, so that too was out.

* The sound files themselves are decoded to PCM by SoundPool when loaded (AudioTrack expects you to supply it with PCM yourself), so as expected there wasn't any performance difference between using OGG and MP3 files. Other things that turned out to not have any discernible impact: sound file sampling rate, sample bit precision, and sound file length.

* Finally, every device we have here (every major manufacturer, most non-major manufacturers, ARM CPUs, Intel CPUs, every Android version from 2.2 - 4.0) turned in similar performance, with one notable exception. The gaming-centric Sony XPERIA Play never blocked the game for longer than 2ms.

Thiago Rosa has found evidence of the sound system shutting down to save power when nothing is playing. Starting a sound would take a long time because everything would need to start back up. Unfortunately, the suggested solution of constantly playing a muted looping sound didn't alter the numbers I was seeing.

Experimenting with AudioTrack is what lead to our shipping implementation. It seems that starting a static AudioTrack is nearly instant. Stopping a static AudioTrack so that you can tell it to refresh and play its contents again (even if the playback was long completed) is what eats up all of the time. My best guess is that all of the time is being spent idling waiting for something between the deeper parts of Android and the hardware to grant access to the AudioTrack.

We ended up moving audio playback onto a different thread from the game logic. Instead of stalling the game while waiting to play a sound, the game simply (and instantly) adds to a buffer the id of a sound effect it wants to play. Each frame, the buffer is handed over to the sound thread where all of the calls to SoundPool.play() happen.

This basically means that the game is free to run whenever the sound thread is stuck waiting.

In the best-case scenario, single-core devices are able to do work during time that was previously spent waiting for the audio system. Multi-core devices may even have the game and sound threads on separate cores, which means the game would be completely isolated from all of sound effect speed bumps.

The worst-case would be if the audio system is actually working hard and not idling while waiting to start a sound. In that case, there is no time to be gained back on a single-core CPU, but we still do have the benefit of not blocking the game thread for extended periods when several sounds start simultaneously.

The downsides to this approach are increased code complexity and an additional game frame (16ms) of latency between the request for a sound to start and when the sound actually starts.

It does bother me a bit that this was ultimately based on an educated guess, but I can say that threading our sound effect playback did restore the missing responsiveness to the game. I would love to have a conversation with someone who really knows the Android audio system to help get to the bottom of it.

I can't say whether our experience would have been any better if we were able to use the NDK. A brief web search indicates that the OpenSL ES implementation there suffers many of the same limitations as AudioTrack/SoundPool in Java, such as 100ms of latency. It would be an interesting point of research to see if starting and stopping sounds there had the same performance penalty.

A future refinement may be to add a priority value to requests in the sound playback queue. This would be so that important sounds (dialog, impact noises, etc.) aren't delayed by a backlog of unimportant ones (ambient sounds) if SoundPool is really running behind. It's not really an issue for Canabalt, but I can see how it would be handy to have.

Monday, March 19, 2012

Generala v1.6

  - Update: Enabled hardware UI acceleration

I reviewed Generala on the Galaxy Nexus and fixed a few minor issues, but all told was pleased to see it's held up just fine even with all the interface changes that have happened.  To that end I updated the SDK version, enabled hardware acceleration, and a few things like that.  this is primarily a maintenence release.

We're part of Humble Android Bundle #2!

Howdy folks, on the fence about Canabalt HD?  Get it as part of the second Humble Android Bundle, and send a portion of the proceeds to charity to boot!

Thursday, March 15, 2012

Canabalt HD

( Android Market link )

We've mentioned working on a game project a couple times here -- the first one we've done in over a year -- and it's finally ready for prime time!  Canabalt HD is an Android-based update to the seminal platform game originally developed by Adam Atomic.  Look for 3D modelled buildings, characters, and backdrops, with the original gameplay left completely intact!


We've stuck faithfully to the color palette and feel of the original game, and hope any fans will be pleased by the graphics update.  If not, you can switch back to the original artwork seamlessly and return to the original old-school sprite look.  Both run well on any Android device running Android 2.2 or above!


As of right now, Canabalt HD is also available for the Kindle Fire, and I'm expecting to have it green-lit on the Nook store shortly.  In addition, it should work and play fine on a GoogleTV device, and we have support for the XPeria Play gamepad to boot.  Everybody wins!




NCAA Jersey Live Wallpaper

( Android Market link )

Adding another one in the NCAA category, looks like our second project there just went live!  This one displays your favorite NCAA team jersey, customized with whatever name and number you'd like!  If you're a fan, check it out!

Wednesday, March 14, 2012

How to Crash a Galaxy S II via the Date Class

We just ran up against this one in a project that's set to launch any day now: a crash that only happened on Samsung Galaxy S II phones, only when set to the Sydney, Australia time zone, and only when using the DD/MM/YYYY date format.

The culprit was eventually tracked down to be the way we were storing time stamps in our text-based save data. This simplified example of what we were doing will crash the above configuration every time:

final Date source = new Date();
final String serialized = source.toString();
final Date dest = new Date( serialized );


The solution was pretty straightforward once we identified the problem. We now store the milliseconds value from the Date object rather than the formatted display text:

final Date source = new Date();
final String serialized = String.valueOf( source.getTime() );
final Date dest = new Date( Long.parseLong(serialized) );


It's a simpler approach and therefore probably what we should have been using since the start, but that's with the benefit of hindsight. The original approach is totally valid according to the Android documentation and survived months of mixed casual and focused testing. It's a pretty good example of one of the weird problems an application can run into out in the wild that are almost impossible to anticipate.

We were extremely lucky to have a someone testing the application in just the right place and with just the right hardware. He snipped a copy of the system log containing the crash from his phone using alogcat. That led us down the path of being able to locally reproduce the problem and ultimately fix it.

Thursday, March 8, 2012

Are you an NCAA Basketball fan? Check this out!

( Android Market link )

We've been working with the folks over a 2Thumbz on a couple of NCAA based projects, and the first one went live last night!  It's an attractive Sports-Center style treatment of the various school logos, with real-time light rays and a selection of different backgrounds.  It's quite good looking in my opinion and well worth a look if you're a fan!

Tuesday, March 6, 2012

Aquarium Live Wallpaper v1.7

  - Update: New background!
  - Update: Two new fish!

This is a content update adding a new background painting, and a couple new fish!  The background is a very cool undersea city painted by Kim Lathrop!

Enjoy!



Saturday, March 3, 2012

Blue Skies Live Wallpaper v2.05

  - New Feature: Set light color (non time of day)
  - Update: Better color swatch pref appearance

A customer pointed out a little while back that while we said in our upsell text you could set the color of the light, in actuality we only let you do that when messing with the time of day.  This is a fair point, and this update adds that feature.

In addition, previously our custom color swatch preference had font sizes that mismatched when you were running Gingerbread -- I've put in a bit of a special case that should help that.  Please let me know if the preference screen looks like gibberish on anyone's device.