Manage audio playback (from the Chinese version of the Android official training course (v0.9.5 ))
If our applications can play audio, it is important for users to control the audio in their expected ways. To ensure a good user experience, we should allow the application to manage the current audio focus, because this ensures that multiple applications do not play audio at the same time.
In this series of courses, we will create an application that can respond to the volume button. This application will request the audio focus when playing the audio, make a correct response when the current audio focus is changed by the system or other applications.
Lessons
Controls the Volume and audio Playback (Controlling Your App's Volume and Playback)
Learn how to ensure that users can adjust the application volume through hardware or software volume controllers (usually these controllers also have playback, stop, pause, Skip, playback, and other function buttons ).
Manage Audio Focus)
Since multiple applications may play audio, it is important to consider how they interact. To prevent multiple music apps from playing Audio at the same time, Android uses Audio Focus to control the playing of Audio. In this lesson, you can learn how to request the audio focus, listen to the loss of the audio focus, and how to respond in this case.
Dealing with Audio Output Hardware)
Audio has multiple output devices. In this lesson, you can learn how to find the device that plays the audio and how to handle the situation where the headset is pulled out during playback.
Control Volume and audio playback
Written by kesenhoo-Original: http://developer.android.com/training/managing-audio/volume-playback.html
Good user experience should be predictable and controllable. If our app can play audio, we obviously need to be able to control the volume through hardware buttons, software buttons, and Bluetooth headsets. Similarly, we need to be able to Play, Stop, Pause, Skip, and Play back audio streams of an application, and ensure its correctness.
Identify Which Audio Stream is used (Identify Which Audio Stream to Use)
To create a sound audio experience, we first need to know which audio streams will be used by the application. Android maintains an independent audio stream for playing music, making an alarm, notifying the bell, calling sound, system sound, calling sound, and dialing sound. The main purpose of this operation is to allow users to independently control different types of audio. Most of the above audio types are restricted by the system. For example, unless your application needs to replace the ringtone of the alarm, you can only play your audio through STREAM_MUSIC.
Use the Hardware Volume key to Control the application Volume (Use Hardware Volume Keys to Control Your App's Audio Volume)
By default, the volume control key is used to adjust the currently activated audio streams. If no sound is played by our application, the volume of the ringtone is adjusted by pressing the volume key. For games or music players, even if there is no sound between songs, or the current game is in a silent State, the user's press on the volume key usually means they want to adjust the volume of the game or music. You may want to adjust the volume of the audio stream by listening to the press event. We don't have to do this. Android provides the setVolumeControlStream () method to directly control the specified audio stream. After identifying which audio stream the application will use, we need to call this method in the early stages of the application lifecycle, because this method only needs to be called once throughout the Activity lifecycle. Generally, we can control multimedia Activity or FragmentonCreate()
Method. This ensures that the audio control function meets user expectations regardless of whether the application is visible or not.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
Since then, regardless of whether the target Activity or Fragment is visible, pressing the volume key of the device can affect the specified audio stream (in this example, the audio stream is "music ").
Use the Hardware Playback Control buttons to Control the application's Audio Playback (Use Hardware Playback Control Keys to Control Your App's Audio Playback)
Many wire control or wireless headphones have many media playback control buttons, such as play, stop, pause, skip, and play back. The system broadcasts an Intent with ACTION_MEDIA_BUTTON no matter you press any control button on the device. To correctly respond to these operations, You need to register a BroadcastReceiver for this Action in the Manifest file, as shown below:
In the implementation of the Receiver er, you need to determine which button the broadcast comes from. Intent includes the information through the EXTRA_KEY_EVENT Key. In addition, the KeyEvent class contains a seriesKEYCODE_MEDIA_*
For example, KEYCODE_MEDIA_PLAY_PAUSE and KEYCODE_MEDIA_NEXT.
public class RemoteControlReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) { KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) { // Handle key press. } } }}
Because there may be multiple programs listening for media button-related events, we must control the timing when the application receives related events in the code. The following example shows how to use AudioManager to register a listener and cancel a media button event for our application. When the Receiver is registered, it will be the only Receiver capable of responding to the media button broadcast.
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);...// Start listening for button pressesam.registerMediaButtonEventReceiver(RemoteControlReceiver);...// Stop listening for button pressesam.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
Generally, applications need to cancel registration listening when they lose focus or are invisible (for example, in the onStop () method. However, it is not that simple for a media playback application. In fact, when the application is invisible (cannot be controlled through a visible UI control, it is extremely important to be able to respond to media play button events. To achieve this, there is a better way to register and cancel listening to audio button events when the program gets and loses the audio focus. This content will be detailed in the subsequent courses.
Manage audio focus
Written by kesenhoo-Original: http://developer.android.com/training/managing-audio/audio-focus.html
Since there may be multiple applications that can play audio, we should consider how they interact. To prevent multiple Audio playback applications from playing Audio at the same time, Android uses the Audio Focus (Audio Focus) to control the playing of Audio-that is, only the application that obtains the Audio Focus can play the Audio.
Before our application starts playing the audio, it needs to first request the audio focus and then obtain the audio focus. In addition, it also needs to know how to listen for events that lose the audio focus and make appropriate responses to these events.
Request the Audio Focus)
Before our app starts playing the audio, it needs to get the audio focus of the audio stream to be used. You can use requestAudioFocus () to obtain the expected audio stream focus. If the request is successful, the method returns AUDIOFOCUS_REQUEST_GRANTED.
In addition, we must specify the audio stream in use and determine whether the requested audio focus is Transient or Permanent ).
Transient focus lock: used when you plan to play a short audio (such as playing navigation instructions ). Permanent focus lock: used when you plan to play a long but predictable audio (such as playing music ).
The following code snippet is an example of requesting a permanent audio focus when playing a music. We must request the audio focus immediately before starting playing it, for example, before a user clicks to play or the background music of the next level in the game starts.
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);...// Request audio focus for playbackint result = am.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN);if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { am.registerMediaButtonEventReceiver(RemoteControlReceiver); // Start playback.}
Once the playback ends, make sure that the abandonAudioFocus () method is called. This is equivalent to notifying the system that we no longer need to obtain the focus and deregister the associated AudioManager. OnAudioFocusChangeListener listener. In another case, releasing the transient audio focus allows any interrupted application to continue playing.
// Abandon audio focus when playback complete am.abandonAudioFocus(afChangeListener);
When requesting a short audio focus, we can choose whether to enable "Ducking ". Normally, an app immediately disables its playing sound when it loses its audio focus. If we choose to enable Ducking when requesting a brief audio focus, it means that other applications can continue playing the video. It is just to reduce the volume at this moment, after obtaining the audio focus again, the normal volume is restored. In other words, ignore this transient focus request, which does not interrupt the currently playing audio. For example, when playing a music, a short text message suddenly prompts a sound. At this time, the volume of the song is only temporarily lowered so that users can hear the text message, after that, the system immediately resumes normal playback ).
// Request audio focus for playbackint result = am.requestAudioFocus(afChangeListener, // Use the music stream. AudioManager.STREAM_MUSIC, // Request permanent focus. AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { // Start playback.}
Ducking is especially suitable for applications that use audio focus intermittently, such as voice navigation.
If another application requests the audio focus as above, the requested permanent or transient audio focus (Ducking or Ducking is not supported ), it will be received by the listener registered when you request to obtain the audio focus.
Handle the Loss of Audio Focus)
If application A requests to obtain the audio focus, the focus obtained by application A will be lost when application B requests to obtain the audio focus. How to respond to a loss of focus event depends on the method of losing focus.
In the listener of the audio focus, the onAudioFocusChange () callback method is triggered when the event that describes the focus change is received. As mentioned earlier, there are three types of focal points to be retrieved. We also have three types of focal points to lose: permanent loss, short loss, and temporary loss, which allow the Ducking to lose temporarily.
Short Focus loss: Normally, when the short focus is lost, the current audio is paused or the volume is reduced. At the same time, you must prepare to Resume playback after getting the focus again.
Lost permanent focus: assuming another app starts playing music, our app should effectively stop itself. In actual scenarios, this means that playing is stopped, media button listening is removed, and the new audio player can only listen to those button events and discard its audio focus. In this case, if you want to resume audio playback, you need to wait for a specific user action (for example, pressing the play button in our app ).
In the following code snippet, if the loss of the Focus type is transient, we pause the audio playback object and restore it after getting the focus again. If it is a permanent focus loss event, our media button listener will be logged out and no longer listen for audio focus changes.
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT // Pause playback } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Resume playback } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { am.unregisterMediaButtonEventReceiver(RemoteControlReceiver); am.abandonAudioFocus(afChangeListener); // Stop playback } }};
In the example of losing short focus above, if Ducking is allowed, in addition to pausing the current playback, we can also choose to use "Ducking ".
Duck!
When Ducking is used, normally played songs will reduce the volume to highlight this short-term audio sound, which not only makes this short-term sound more prominent, but will not interrupt the normal sound.
The following code snippet reduces the volume when the player temporarily loses the audio focus and restores the original volume after obtaining the audio focus again.
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() { public void onAudioFocusChange(int focusChange) { if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { // Lower the volume } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Raise it back to normal } }};
The loss of audio focus is one of the most important event broadcasts that we need to respond to, but there are many other important broadcasts that we need to correctly respond. The system broadcasts a series of Intent messages to notify you of the various changes in the use of audio. The next lesson demonstrates how to listen to these broadcasts and improve the overall user experience.
Compatible with audio output devices
Written by kesenhoo-Original: http://developer.android.com/training/managing-audio/audio-output.html
When users want to enjoy music through Android devices, they can have a variety of options. Most devices have built-in speakers, wired headphones, and many other devices support Bluetooth connections, some even support A2DP Bluetooth audio transmission model protocols. The full name of A2DP is "Advanced Audio Distribution Profile! A2DP uses a chip in the headset to stack data to achieve high sound definition. A headset with A2DP is a Bluetooth stereo headset. The sound can reach 44.1 kHz, and the average earphone can only reach 8 kHz. If the mobile phone supports Bluetooth, you only need to load the A2DP protocol to use the A2DP headset. Also, the consumer saw the technical parameter mention Bluetooth V1.0 V1.1 V1.2 V2.0-these refer to the technical version of Bluetooth and refer to the speed of transmission through Bluetooth, whether they support A2DP depends on whether the Bluetooth Product Manufacturer uses this technology. From Baidu encyclopedia)
Check What Hardware is Being Used)
Playing sound with different hardware will affect the behavior of applications. You can use AudioManager to query whether the current audio is output to the speaker, wired headset, or Bluetooth, as shown below:
if (isBluetoothA2dpOn()) { // Adjust output for Bluetooth.} else if (isSpeakerphoneOn()) { // Adjust output for Speakerphone.} else if (isWiredHeadsetOn()) { // Adjust output for headsets} else { // If audio plays and noone can hear it, is it still playing?}
Handle Changes in the Audio Output Hardware)
When a wired headset is pulled out or the bluetooth device is disconnected, the audio stream is automatically output to the built-in speaker. Assuming that the playing sound is very loud, it will appear very noisy to suddenly switch to the speaker.
Fortunately, the System Broadcasts Intent with ACTION_AUDIO_BECOMING_NOISY in this case. Whenever you play the audio, we should register a BroadcastReceiver to listen to this Intent. When using a music player, you usually want to pause playing the current song. In games, users usually want to reduce the volume.
private class NoisyAudioStreamReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) { // Pause the playback } }}private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);private void startPlayback() { registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);}private void stopPlayback() { unregisterReceiver(myNoisyAudioStreamReceiver);}