Google Android Development Agency SASS

Friday 27 November 2009

Android AudioTrack source

I've been doing a lot of work optimising our audio playback on Tub Thumper Pro for Android this week and I constantly find myself referring back to the C++ source for the OS to help solve latency issues.

For anyone doing work with the AudioTrack object, it's worthwhile bookmarking the source online so that you can browse it whenever you hit a problem.

Here's two links I find really useful:

Incidentally, I've found that the best way of getting low-latency polyphonic audio is to subclass AudioTrack and call finalize() yourself after you're done playing; I was seeing more "write blocked for xx seconds" messages before I did this, although it may be co-incidental.

Thursday 26 November 2009

Useful tool for building Android user interfaces

Android user interfaces are built using XML and the support for graphically laying these out in Eclipse is limited to say the least. (There are many things wrong with Visual Studio .NET but at least the UI builder is reasonably well sorted...)

A while back I came across DroidDraw - a third party tool for prototyping UIs. I think I must have had an early build back then because it had some issues, but I downloaded the latest build today and it's now hugely useful.

If you want to throw some Android user interfaces together head over to http://droiddraw.org/ and try it out. It's the tool Google should have included with the SDK!

Tuesday 24 November 2009

Android Activity States and State Transitions

I wanted to tidy a bit of our Android code up recently to make sure that each Activity was handing it's state properly and to make sure that things were getting cleaned up when the Activity was done.

Before doing this it was important to fully understand the lifecycle of an Android Activity and to understand the state transitions that will and can occur within one.

An Android activity basically exists in one of four states:


Here's a bit more detail about each of these states:

Active
The Activity is in the foreground of the screen and is interacting with the user

Paused
The Activity has temporarily lost focus behind a new non-fullscreen or transparent Activity. In this state is retains all of it's state, however, if Android detects a low-memory situation it may be killed.

Stopped
The Activity is totally obscured behind another Activity. Again it retains it's state, but is much more likely to be killed at any point.

Finished
The Activity has been closed, either by Android or by calling finish(). The state it had dies at this point (unless you explicitly save it).


There are seven events in the Android Activity Lifecycle which give you a bit of control over what happens during each state transition.

onCreate(Bundle icicle)
Fires when the Activity is first launched. You would normally do all of your setup in this method. You can also retrieve any previously saved state from the supplied Bundle.

onStart()
Called when the Activity is becoming visible to the user, for example when another Activity higher in the stack has closed.

onRestart()
Called after the Activity has been stopped and is being restarted.

onResume()
Called when the Activity is becoming interactive to the user.

onPause()
Called when Android is about to start resuming another Activity. You would normally use this to stop anyting dynamic that is happening in your Activity, e.g sounds playing, animations happening.

onStop()
Called when the Activity is no longer visible, usually because another Activity has started over the top of it.

onDestroy()
This is the last breath of your Activity, called just before Android pulls the plug on it.

Here's a state transition diagram to show the sequence of states and the events in between:



isDaemon and Java Threads

Whilst pondering the best way to organise the threading structure of our upcoming Android app Tub Thumper Pro, it struck me that there is a smattering of confusion (at least in my head!) over whether a thread is a daemon or not.

In Java, there are two types of threads Daemon Threads and User Threads.

User Threads are the ones you'll most commonly use; these provide the mechanism of running parallel code in your applications. Most importantly - when the application is terminated, the JVM waits for all user threads to finish before quitting.

Daemon Threads are generally used for service-level processing rather than application-level code. The JVM will not wait for any daemons to finish before quitting your application, they will run behind the scenes until the JVM decides there's nothing else to do and terminates.



Monday 23 November 2009

Low latency audio playback in Android

One of the things which bugged me immensely about Android was it's lack of low-latency audio playback and a low-level audio API.

Unlike the iPhone, Android developers were stuck with high-level media player objects which basically only allowed you to chuck an MP3/OGG/Wav their way and hope for the best.

Well not any more my robot loving amigos!

After pulling my hair out trying different designs and playback algorithms working on the sequencing function of Tub Thumper Pro for Android, I finally found what I'd been looking for; an object for working with sample-level data, just like we've been doing on the iPhone.

android.Media.AudioTrack

I mean, it's not perfect, but here's what we're doing to run samples directly to the hardware without all of that mediaplayer-esque overhead (I've edited it to make it make sense outside of our app, but the theory is there):


//--load the sound file from the resource identifier into a byte array (c is Context)
InputStream s = c.getResources().openRawResource(resourceFile);
soundData = new byte[s.available()];
s.read(soundData);

//--setup an AudioTrack object, this one is running at 44.1Khz which worked best for us.
AudioTrack oTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT, intSize,AudioTrack.MODE_STREAM);

//--turn the audiotrack on
oTrack.play();
//--write something to the audio track, in this case the entire buffer
int playVal = oTrack.write(soundData,0,soundData.length);
//--we're turning it off here
oTrack.stop();

Our Android app in Top 100 Best Smartphone apps of all time!

Well oil my bike. Our first Android app, Tub Thumper, has just been listed in the "Hot 100 best apps" by T3 Magazine.

We still get plenty of feedback about the free version (mostly positive thankfully) and we're trying to get the Pro version out ASAP.

I'll be very interested in seeing how it runs on my Motorola Droid phone, when it arrives, given it has a multitouchscreen...

You can view the gallery here: http://www.t3.com/feature/t3s-hot-100-apps


Update - here's a shot of the app at number 1 in this months T3 magazine!

Google Chrome OS Beta first install

No posts for a few months, mainly due to the lack of mobile development action over here!

Just downloaded the first build of Google Chrome-OS and installed it on a VMWare virtual machine.

First impressions: Booted up very very quickly. I can definitely see the use for it in low-cost netbooks and for couch surfing. However, there are a couple of things which I can foresee might scupper it: No iTunes/Media playing and no image editing. All very well sticking your photos on Picasa or Flickr, but how are you supposed to get them off your device and edit them without any means of installing desktop editing software, or without provision for storing files locally?

I currently use a Macbook for surfing on the couch and for dragging photos off my cameras and onto Flickr. I would have considered Chrome-OS an alternative for this (farewell Apple at last...) but without just a few more niceties I can't make that switch.

Anyway, here's some screenshots of the login screen and the first screens you'll see.






All those apps you see above are of course just links to websites, although Google have mentioned in their design documents that they are hoping to use popups for sub-tasks, like the one shown below.



If you want to try it yourself, head over to http://discuss.gdgt.com/google/chrome-os/general/download-chrome-os-vmware-image/ and grab the VMWare image. (If you have trouble logging into the virtual machine, try the username "chronos" without a password).