Game Development Reference
In-Depth Information
The
AndroidAudio
implementation has an
AssetManager
and a
SoundPool
instance. The
AssetManager
is necessary for loading sound effects from asset files into the
SoundPool
on a call
to
AndroidAudio.newSound()
. The
AndroidAudio
instance also manages the
SoundPool
.
public
AndroidAudio(Activity activity) {
activity.setVolumeControlStream(AudioManager.
STREAM_MUSIC
);
this
.assets=activity.getAssets();
this
.soundPool=
new
SoundPool(20, AudioManager.
STREAM_MUSIC
, 0);
}
There are two reasons why we pass our game's
Activity
in the constructor: it allows us to
set the volume control of the media stream (we always want to do that), and it gives us an
AssetManager
instance, which we will happily store in the corresponding class member.
The
SoundPool
is configured to play back 20 sound effects in parallel, which is adequate for
our needs.
public
Music newMusic(String filename) {
try
{
AssetFileDescriptor assetDescriptor=assets.openFd(filename);
return new
AndroidMusic(assetDescriptor);
}
catch
(IOException e) {
throw new
RuntimeException("Couldn't load music '"+filename+"'");
}
}
The
newMusic()
method creates a new
AndroidMusic
instance. The constructor of that class
takes an
AssetFileDescriptor
, which it uses to create an internal
MediaPlayer
(more on that
later). The
AssetManager.openFd()
method throws an
IOException
in case something goes
wrong. We catch it and rethrow it as a
RuntimeException
. Why not hand the
IOException
to
the caller? First, it would clutter the calling code considerably, so we would rather throw a
RuntimeException
that does not have to be caught explicitly. Second, we load the music from
an asset file. It will only fail if we actually forget to add the music file to the assets/directory, or
if our music file contains false bytes. False bytes constitute unrecoverable errors since we need
that
Music
instance for our game to function properly. To avoid such an occurrence, we throw
RuntimeException
s instead of checked exceptions in a few more places in the framework of
our game.
public
Sound newSound(String filename) {
try
{
AssetFileDescriptor assetDescriptor=assets.openFd(filename);
int
soundId=soundPool.load(assetDescriptor, 0);
return new
AndroidSound(soundPool, soundId);
}
catch
(IOException e) {
throw new
RuntimeException("Couldn't load sound '"+filename+"'");
}
}
}
Finally, the
newSound()
method loads a sound effect from an asset into the
SoundPool
and returns
an
AndroidSound
instance. The constructor of that instance takes a
SoundPool
and the ID of the