Android - 音频焦点学习

在做蓝牙带屏音箱项目的时候,碰到一个问题,具体是在连接蓝牙音箱回连的时候,播放音乐会在手机端点击播放过一会就回被暂停。

调试了一下问题后,大概问题是这样的,一般情况下,我们在播放音乐时会请求系统音频焦点,然后在不播放的时候释放焦点。

我也是按照这种逻辑处理的,但和一般情况不同的是,我应用所在的底层系统是经过定制的,而在音频焦点的处理上,除了我上层应用会在蓝牙播放变化的时候请求焦点,底层的系统也会做同样的操作,这就造成了在两者来回请求的过程中,焦点丢失了。

这种问题还是比较少见的,所以记录一下,而最终的解决办法是让提供定制系统的硬件方解决。不过这里也记录一下对于音频焦点请求和监听的学习。

完整的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class MusicService extends Service {
private AudioManager mAm;
private boolean isPlaymusic;
private String url;
private MediaPlayer mediaPlayer;
@Override
public void onCreate() {
super.onCreate();
mAm = (AudioManager) getSystemService(AUDIO_SERVICE);
}
@Override
public void onStart(Intent intent, int startId) {
if (intent != null) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
isPlaymusic = bundle.getBoolean("isPlay", true);
url = bundle.getString("url");
if (isPlaymusic)
play();
else
stop();
}
}
}
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
pause();
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
resume();
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
// mAm.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
mAm.abandonAudioFocus(afChangeListener);
// Stop playback
stop();
}
}
};
private boolean requestFocus() {
// Request audio focus for playback
int result = mAm.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
private void resume() {
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
private void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
}
OnCompletionListener completionListener = new OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer player) {
if(!player.isLooping()){
mAm.abandonAudioFocus(afChangeListener);
}
}
};
private void play() {
if (requestFocus()) {
if (mediaPlayer == null) {
try {
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(completionListener);
} catch (IOException e) {
e.printStackTrace();
}
}
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null)
mediaPlayer.release();
}
private void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
}
}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}

需要解释一下的是,在 onAudioFocusChange 方法里的返回值代表了当前焦点变化的状态

常量 说明
AUDIOFOCUS_GAIN 持有焦点
AUDIOFOCUS_LOSS 失去焦点
AUDIOFOCUS_LOSS_TRANSIENT 临时失去焦点
AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK 临时失去焦点,允许小声播放