Playing audio

Many apps, especially games, have sounds. This can just be a feedback sound or one that enhances the navigation or interaction of the game. Games usually have background music playing on a loop.

How to do it...

The MediaPlayer type is used to play a sound from a content provider, a URI or a resource:

  1. To play a sound from included resources or a Uri instance, we use the static Create() method on MediaPlayer:
    var mediaPlayer = MediaPlayer.Create(
      this, Resource.Raw.SoundResource);  
  2. Then, because we need to be able to clean up after the sound is finished, we subscribe to the Completion event and release the player:
    mediaPlayer.Completion += delegate {
      mediaPlayer.Release();
      mediaPlayer = null;
    };
  3. To begin playing, either from a paused or prepared state, we invoke the Start() method:
    mediaPlayer.Start();
  4. Finally, we can control the player using the Pause() and Stop() methods:
    mediaPlayer.Pause();
    mediaPlayer.Stop();

If we want to stream sound from an asset or a remote URI, we construct a new MediaPlayer object, which sets various options before starting:

  1. For more control over how and what is played, we use the MediaPlayer constructor:
    var mediaPlayer = new MediaPlayer();
  2. Before we can play sound, we have to specify what type of sound will be played. The most common is Music, so lets execute the following code to add sound in our project:
    mediaPlayer.SetAudioStreamType(Stream.Music);
  3. We can play a file out of the app assets by passing the FileDescriptor to the SetDataSource() method:
    var fd = Assets.OpenFd("SoundAsset.mp3");
    mediaPlayer.SetDataSource(
      fd.FileDescriptor, fd.StartOffset, fd.Length);
    fd.Close();

    Alternatively, we could play a file from a content provider or remote URI using the SetDataSource() method as well:

    var uri = "http://example.org/audio.mp3");
    mediaPlayer.SetDataSource(uri);
  4. Again, we may want to clean up the player when the playback is complete, if we aren't going to use it again:
    mediaPlayer.Completion += delegate {
      mediaPlayer.Release();
      mediaPlayer = null;
    };
  5. In case of any errors, we will have to reset the player before we can use it again:
    mediaPlayer.Error += delegate {
      mediaPlayer.Reset();
    };
  6. Before the audio can be played, it has to be prepared. As this takes some time, it has to be done on a separate thread, using the PrepareAsync() method. When the preparation is complete, the playback can be started:
    mediaPlayer.Prepared += delegate {
      mediaPlayer.Start();
    };
    mediaPlayer.PrepareAsync();
  7. If we are already on another thread, we can just invoke the synchronous Prepare() method and then use the Start() method to begin the playback:
    mediaPlayer.Prepare();
    mediaPlayer.Start();

How it works...

If we want to play audio, we make use of the MediaPlayer type, which provides all the tools needed to play media. Media can be streamed from local sources, such as the file system, and remote sources, such as internet streaming.

Note

The MediaPlayer type can play both video and audio from either local or remote sources.

For the most simplest of cases, we can just make use of the convenient static Create() method overloads. This method will automatically prepare the player, and once the method returns, we can start playing the audio. The Create() method can load and prepare local audio, for example a packaged resource or a URI, such as that from a content provider or the file system.

Note

The Create() method will automatically prepare the media player.

The MediaPlayer object is quite expensive and should be disposed of as soon as we are finished with it. We let the system know that it should clean up the resources by invoking the Release() method. If we are creating a sound that will be played once, we can attach an event handler to the Completion event, which will allow us to clean up as soon as the event is fired. If the player is stopped before the end of the file, the Completion event will not be triggered, and we will have to release the player ourselves.

We can control the player through the various methods available. The most basic is Start, which will start the player, and Stop, which will stop the playback. If we stop the playback, we will have to prepare the player before we can start playing again. If we invoke the Pause() method, playback is paused and can be resumed by the Start() method without having to prepare the player.

Note

If the player is stopped, the Completion event will not be triggered and the player will have to be prepared again before resuming.

If we want to jump to a specific location in the playback, we can use the SeekTo() method. This method is asynchronous and moves the playback to the specified millisecond location. If we want to be notified about the completion of the seek, we can subscribe to the SeekCompleted event. Seeking is asynchronous as we may have to wait for the buffer to load enough data before playing.

Tip

The SeekTo() method is asynchronous as the media may be streaming over a network.

To have greater control over what, and how, audio is played, we can use the default MediaPlayer constructor. This provides us with a player that is not already set up and ready to play. If we use the constructor, we will have to set the audio type using the SetAudioStreamType() method. The audio stream type can be, but is not limited to, Stream.Music, Stream.Alarm, or Stream.Notification, depending on what we will play. For most cases, Stream.Music will be used.

Creating the MediaPlayer instance through the constructor allows us to play files from stream-based locations, such as the assets or a remote URL. To play a file from the assets, we can open the FileDescriptor instance and then pass it to the SetDataSource() method. Similarly, we can pass either a string or an Uri instance to the SetDataSource() method to specify what should be played.

Note

The default constructor does not prepare the player and has to be done manually.

As there may be a problem during the execution of asynchronous methods, we can subscribe to the Error event. This allows us to receive notifications when an error occurs. If there is an error, the player goes into an invalid state and will have to be reset using the Reset() method before we can perform any other operations.

Before we can play the audio, we have to prepare the player. We can do this either asynchronously or synchronously. If we prepare the player synchronously, it will block the current thread. If the player is streaming from a remote source, this may take some time; thus, it should always be done on a separate thread.

If we prepare the player asynchronously, it will not block the UI and will trigger the Prepared event on completion. We can use this event to start the audio playback immediately, or we can delay the playback until a later time. To prepare asynchronously, we invoke the PrepareAsync() method, and to prepare synchronously, we invoke the Prepare() method.

Tip

Preparing the player may take some time, especially if the source is on a network. Thus, PrepareAsync should always be used on the UI thread.

There's more...

The SoundPool instance can also be used for small audio clips. It can repeat or play several sounds simultaneously. Sounds are loaded asynchronously, but should not exceed 1 MB.

Sounds are loaded using the Load() method, which returns an ID that is used by the Play() method to start the playback of that sound. The Play() method returns another ID, which we use to control the playback through the Pause() and Resume() methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset