Handling audio focus
Even though only one activity can run at any given time, Android is amulti-tasking environment. This poses a particular challenge to applications that use audio, because there is only one audio output and there may be several media services competing for its use. Before Android 2.2, there was no built-in mechanism to address this issue, which could in some cases lead to a bad user experience. For example, when a user is listening to music and another application needs to notify the user of something very important,the user might not hear the notification tone due to the loud music. Starting withAndroid 2.2, the platform offers a way for applications to negotiate their use of the device's audio output. This mechanism is called Audio Focus.
雖然在任意一個給定時間,隻有一個activity能運作,android也是一個多任務環境。這給應用程式使用音頻帶來了一個特殊的挑戰,因為隻有一個音頻輸出,并且可能有幾個媒體服務争奪使用這個音頻輸出。在Android 2.2之前,沒有内建的機制來解決這個問題,這個問題在一些case下能導緻一個壞的使用者體驗。例如,在使用者正在聽音樂時,其他應用需要通知使用者非常重要的事情,使用者可能不會聽到通知鈴聲,因為聲音很大的音樂。從Android 2.2 開始,平台提供一個方法為應用,為了讓這些播放音頻的應用協調他們如何使用裝置的音頻輸出。這個機制被叫做音頻焦點。
When your application needs to output audio such as music or a notification,you should always request audio focus. Once it has focus, it can use the sound output freely, but it should always listen for focus changes. If it is notified that it has lost the audiofocus, it should immediately either kill the audio or lower it to a quiet level(known as "ducking"—there is a flag that indicates which one is appropriate) and only resumeloud playback after it receives focus again.
當你的應用需要輸出像是音樂或者通知這樣的音頻,你總是應該請求音頻焦點。一旦你的app擁有焦點,它就能自由的使用聲音輸出,但是它應該總是監聽焦點的改變。如果它被通知它已經失去了音頻焦點,它就應該立即殺掉音頻或者降低它的音量到靜音的水準(被稱為“ducking”- 有一個标記,用來表明哪一個是适合的),并且隻能在它接收到焦點再次擷取時恢複回放。
Audio Focus is cooperative in nature. That is, applications are expected(and highly encouraged) to comply with the audio focus guidelines, but the rules are not enforced by the system. If an application wants to play loud music even after losing audio focus, nothing in the system will prevent that.However, the user is more likely to have a bad experience and will be more likely to uninstall the misbehaving application.
音頻焦點本質上是合作機制。這就是,應用被期望遵守音頻焦點指導方針,但是這個規則不是被系統強力執行的。如果一個應用想要繼續大聲播放音樂,甚至在失去音頻焦點後,系統中不會有任何東西來阻止它。然而,使用者更可能有一個壞的體驗,并且将會更可能解除安裝掉這樣行為不端的應用。
To request audio focus, you must call
requestAudioFocus()
from the
AudioManager
, as the example below demonstrates:
為了請求音頻焦點,你必須從AudioManager調用 requestAudioFocus() 函數 , 像下面示範的例子:
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// could not get audio focus.
}
The first parameter to
requestAudioFocus()
is an
AudioManager.OnAudioFocusChangeListener
,whose
onAudioFocusChange()
method is called whenever there is a change in audio focus. Therefore, you should also implement this interface on your service and activities. For example:
requestAudioFocus() 函數的第一個參數時一個監聽:AudioManager.OnAudioFocusChangeListener, 這個監聽的onAudioFocusChange()方法會被調用,在音頻焦點有改變的時候。是以,你也應該實作這個接口,在你的service和activity裡。例如:
class MyService extends Service
implements AudioManager.OnAudioFocusChangeListener {
// ....
public void onAudioFocusChange(int focusChange) {
// Do something based on focus change...
}
}
The
focusChange
parameter tells you how the audio focus has changed, and can be one of the following values (they are all constants defined in
AudioManager
):
focusChange 參數告訴你音頻焦點有怎樣的改變,這個改變能是以下值中的一個(它們所有都被定義在 AudioManager裡);
-
: You have gained the audio focus.AUDIOFOCUS_GAIN
音頻焦點擷取:你已經擷取到音頻焦點。
-
: You have lost the audio focus for a presumably long time.You must stop all audio playback. Because you should expect not to have focus back for a long time, this would be a good place to clean up your resources as much as possible. For example, you should release theAUDIOFOCUS_LOSS
.MediaPlayer
音頻焦點失去:你已經可能在很長時間裡失去音頻焦點。你必須停止所有音頻回放。因為你應該預料到在很長時間裡不會有焦點回來 , 這應該是一個盡可能清理你的 資源的好地方。例如,你應該釋放MediaPlayer。
-
: You have temporarily lost audio focus, but should receive it back shortly. You must stop all audio playback, but you can keep your resources because you will probably get focus back shortly.AUDIOFOCUS_LOSS_TRANSIENT
音頻焦點瞬時失去:你已經臨時失去音頻焦點,但是很快應該會接收到焦點傳回。你必須停止所有音頻回放,但是你能保持你的資源不變,因為你将可能很快再次獲得焦點。
-
: You have temporarily lost audio focus,but you are allowed to continue to play audio quietly (at a low volume) instead of killing audio completely.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
音頻焦點瞬時失去帶閃避:你已經臨時的失去音頻焦點,但是你被允許繼續小聲的播放音頻,代替完全的殺掉音頻播放。
Here is an example implementation:
這裡是一個例子實作:
public void onAudioFocusChange(int focusChange) {
switch (focusChange) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
if (mMediaPlayer == null) initMediaPlayer();
else if (!mMediaPlayer.isPlaying()) mMediaPlayer.start();
mMediaPlayer.setVolume(1.0f, 1.0f);
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mMediaPlayer.isPlaying()) mMediaPlayer.stop();
mMediaPlayer.release();
mMediaPlayer = null;
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mMediaPlayer.isPlaying()) mMediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mMediaPlayer.isPlaying()) mMediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
Keep in mind that the audio focus APIs are available only with API level 8 (Android 2.2)and above, so if you want to support previous versions of Android, you should adopt a backward compatibility strategy that allows you to use this feature if available, and fall back seamlessly if not.
記住音頻焦點的api隻在api等級8或者更高的等級上可用。是以如果你想要支援前一個版本的Android,你應該采取一個向後相容的政策,這個政策是如果它可用,就會允許你使用這個功能,如果不可用,無縫回落。
You can achieve backward compatibility either by calling the audio focus methods by reflectionor by implementing all the audio focus features in a separate class (say,
AudioFocusHelper
). Here is an example of such a class:
你能獲得向前相容,或通過調用音頻焦點方法,通過反射,通過在一個單獨的實作了所有音頻焦點功能的類檔案裡。這裡是這樣一個類的例子:
public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {
AudioManager mAudioManager;
// other fields here, you'll probably hold a reference to an interface
// that you can use to communicate the focus changes to your Service
public AudioFocusHelper(Context ctx, /* other arguments here */) {
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
// ...
}
public boolean requestFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.requestAudioFocus(mContext, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
}
public boolean abandonFocus() {
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
mAudioManager.abandonAudioFocus(this);
}
@Override
public void onAudioFocusChange(int focusChange) {
// let your service know about the focus change
}
}
You can create an instance of
AudioFocusHelper
class only if you detect that the system is running API level 8 or above. For example:
你能建立一個AudioFocusHelper類的執行個體 , 如果你檢測到系統是運作在api等級8 或者更高等級上。例如:
if (android.os.Build.VERSION.SDK_INT >= 8) {
mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);
} else {
mAudioFocusHelper = null;
}