Managing the audio volume

When we play music, for example in a media player or game, we need to be able to control the volume based on what the user is doing. For example, if the user receives a call, the music should be paused. If there is an alarm, the volume should drop.

How to do it...

We can respond to various system requests to reduce the volume of media. One instance of this is when the headphones are removed, we may wish to pause the playback so as to avoid unexpected loud sounds:

  1. If we want to pause music when the headphones are removed, we can respond to the ActionAudioBecomingNoisy instance broadcast and pause the playback:
    [BroadcastReceiver]
    [IntentFilter(
      new[]{ AudioManager.ActionAudioBecomingNoisy })]
    public class MediaReceiver : BroadcastReceiver {
      public override void OnReceive(
      Context context, Intent intent) {
        context.StartService(new Intent(
          MediaService.ActionPause, null, context,
          typeof(MediaService)));
      }
    }

Also, we can respond to requests from other apps to reduce the sound volume, or request other apps reduce their volume for our app:

  1. We can listen for audio focus changes by registering with the AudioManager instance. First, the AudioManager.IOnAudioFocusChangeListener interface needs to be implemented, allowing us to be notified of focus changes:
    public class MediaService : Service,
    AudioManager.IOnAudioFocusChangeListener {
      public void OnAudioFocusChange(AudioFocus focusChange) {
      }
    }
  2. Next, we will need a reference to the AudioManager instance:
    manager = AudioManager.FromContext(ApplicationContext);
  3. Then, when we start playing music, we pass the interface implementation to the RequestAudioFocus() method on AudioManager. We use the AudioFocus.Gain value to indicate that we want to gain focus, as follows:
    var request = manager.RequestAudioFocus(
      this, Stream.Music, AudioFocus.Gain);
    if (request != AudioFocusRequest.Granted) {
      // handle any failed requests
    }
  4. Similarly, we can release audio focus by passing the same interface implementation to the AbandonAudioFocus() method, as follows:
    var abandon = manager.AbandonAudioFocus(this);
    if (abandon != AudioFocusRequest.Granted) {
      // handle any failed requests
    }
  5. As soon as another app, such as the dialer during an incoming call, requests focus, we can respond through the OnAudioFocusChange() method:
    switch (audioFocus) {
      case AudioFocus.Gain:
        mediaPlayer.SetVolume(1.0f, 1.0f);
        break;
      case AudioFocus.Loss:
        StopPlaying();
        CleanUpPlayer();
        break;
      case AudioFocus.LossTransient:
        PausePlaying();
        break;
      case AudioFocus.LossTransientCanDuck:
        mediaPlayer.SetVolume(0.25f, 0.25f);
        break;
    }

How it works...

Playing audio, whether in the background or in the foreground, needs to work with other apps on the device as well as with the users in their environments.

An example of working with the user is to ensure that the audio stays at the same level with regards to the environment. If the user is using headphones, the actual environment has no sound as all the sound is contained inside the headphones. When the user removes the headphone jack, the environment should not suddenly receive additional loud audio from the device. We can do this by stopping the playback when the Android system determines that the current state of audio will affect the environment. To be notified of such events, we have to listen for the ActionAudioBecomingNoisy broadcast.

Tip

The ActionAudioBecomingNoisy broadcast can be used to pause the playback if the headphones are removed from the device, preserving the audio level of the environment.

In the case of working with other apps on the device, we can ensure that the user is notified, or the user's attention is shifted from our activity to one that is more important. An example would be to shift the user's attention to an incoming call or an important notification.

This is done by requesting and listening for requests to shift audio focus. Shifting audio focus means that when there is a more important audio that needs to be played, we either lower the volume of our audio or we stop our audio completely. Determining whether we can lower the volume, or if we should just stop the playback is determined by the type of audio focus requested.

To start receiving audio focus messages, we first need to request focus. When we request focus, we need to provide the AudioManager instance with an implementation of the IOnAudioFocusChangeListener interface. We pass this to the RequestAudioFocus() method along with two other parameters. The second parameter specifies the type of audio that will be affected by the focus shift. The last parameter specifies the type of focus that is to be obtained. There are several focus types:

Type

Description

Example Usage

Gain

This gets focus for an unknown duration

Music

GainTransient

This gets focus for a short period

Driving directions

GainTransientMayDuck

This gets focus for a short period, but the other audio does not have to stop, only lower their volume

Notifications

GainTransientExclusive

This gets focus for a short period, and the system will not play any sounds

Speech recognition

If we request the Gain audio focus, the other apps will stop their audio as we might be requesting focus for a long time. By requesting GainTransient or GainTransientExclusive, other apps will stop their audio, but still hold onto their resources as we would be releasing the focus shortly. By requesting GainTransientExclusive, the system will also stop its audio. When we request GainTransientMayDuck, other apps will simply lower their volume so that ours can be heard more clearly.

If we have focus, we should release the focus once we have completed our playback, for example, when the player is stopped or paused by the user. Releasing focus is done using the AbandonAudioFocus() method and allows the other apps to resume or continue with what ever they were doing before we requested focus.

The IOnAudioFocusChangeListener interface has a single method, OnAudioFocusChange, which will receive one of the incoming audio focus request types:

Focus Request Type

Description

Gain

This indicates that we have received audio focus

Loss

This indicates that we have lost audio focus for an unknown duration

LossTransient

This indicates that we have lost audio focus for a short period

LossTransientMayDuck

This indicates that we have lost audio focus, but we may just lower our volume

If we receive the Loss audio focus message, we should stop and release the player resources as we may not get the focus back for a long time. When we receive the LossTransient message, we can just pause the player as we may resume in a very short period of time. The LossTransientMayDuck message means that we can continue to play but at a lower volume. We can lower the volume of our player by passing a value in the 1.0 to 0.0 range to the SetVolume() method, with 1.0 representing full volume.

There's more...

Requesting focus is very useful if will be recording audio or video. We don't want the sound from the device to override the incoming sound from the microphone. Also, if we are going to make use of the text-to-speech features, we don't want the music to hinder the listener's ability to understand what is being read out.

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

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