NIMSDK-AOS  9.19.0
AudioPlayer.java
浏览该文件的文档.
1 package com.netease.nimlib.sdk.media.player;
2 
3 import android.content.Context;
4 import android.media.AudioManager;
5 import android.media.AudioManager.OnAudioFocusChangeListener;
6 import android.media.MediaPlayer;
7 import android.media.MediaPlayer.OnCompletionListener;
8 import android.media.MediaPlayer.OnErrorListener;
9 import android.media.MediaPlayer.OnPreparedListener;
10 import android.os.Handler;
11 import android.os.Message;
12 import android.text.TextUtils;
13 
14 import com.netease.nimlib.log.NimLog;
15 
16 import java.io.File;
17 
18 /**
19  * 和AudioRecorder对应音频播放器。<br>
20  * AudioRecorder的录音格式可以是aac,但在低版本系统上,MediaPlayer是不支持aac格式的。这个类对aac格式做了兼容处理。<br>
21  * 同时针对会话场景的语音播放,将MediaPlayer的回调接口做了封装,以方便使用。
22  */
23 public final class AudioPlayer {
24  public static final String TAG = "AudioPlayer";
25 
26  private MediaPlayer mPlayer;
27 
28  private String mAudioFile;
29 
30  private long mIntervalTime = 500L;
31 
32  private AudioManager audioManager;
33 
34  private OnPlayListener mListener;
35 
36  private int audioStreamType = AudioManager.STREAM_VOICE_CALL;
37 
38  private static final int WHAT_COUNT_PLAY = 0x000;
39 
40  private static final int WHAT_DECODE_SUCCEED = 0x001;
41 
42  private static final int WHAT_DECODE_FAILED = 0x002;
43 
44  /**
45  * 音频播放器构造函数
46  * @param context 上下文参数
47  */
48  public AudioPlayer(Context context) {
49  this(context, null, null);
50  }
51 
52  /**
53  * 音频播放器构造函数
54  * @param context 上下文参数
55  * @param audioFile 待播放音频的文件路径
56  * @param listener 播放进度监听者
57  */
58  public AudioPlayer(Context context, String audioFile, OnPlayListener listener) {
59  audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
60  mAudioFile = audioFile;
61  mListener = listener;
62  }
63 
64  /**
65  * 设置音频来源
66  *
67  * @param audioFile 待播放音频的文件路径
68  */
69  public void setDataSource(String audioFile) {
70  if (!TextUtils.equals(audioFile, mAudioFile)) {
71  NimLog.audio("start play audio file" + audioFile);
72  mAudioFile = audioFile;
73  }
74  }
75 
76  /**
77  * 设置播放监听
78  *
79  * @param listener
80  */
81  public void setOnPlayListener(OnPlayListener listener) {
82  mListener = listener;
83  }
84 
86  return mListener;
87  }
88 
89  /**
90  * 开始播放
91  * @param audioStreamType 设置播放音频流类型, 用于切换听筒/耳机播放 取值见android.media.AudioManager
92  */
93  public void start(int audioStreamType) {
94  this.audioStreamType = audioStreamType;
95  startPlay();
96  }
97 
98  /**
99  * 停止播放
100  */
101  public void stop() {
102  if (mPlayer != null) {
103  endPlay();
104  if (mListener != null) {
105  mListener.onInterrupt();
106  }
107  }
108  }
109 
110  /**
111  * 查询是否正在播放
112  *
113  * @return 如果为true,表示正在播放,否则没有播放
114  */
115  public boolean isPlaying() {
116  try {
117  return mPlayer != null && mPlayer.isPlaying();
118  } catch (Throwable e) {
119  e.printStackTrace();
120  NimLog.e(TAG, "isPlaying error", e);
121  return false;
122  }
123  }
124 
125  /**
126  * 获取音频持续时间长度
127  *
128  * @return 持续时间
129  */
130  public long getDuration() {
131  if (mPlayer != null) {
132  try {
133  return mPlayer.getDuration();
134  } catch (Throwable e) {
135  e.printStackTrace();
136  NimLog.e(TAG, "getDuration error", e);
137  return 0;
138  }
139  } else {
140  return 0;
141  }
142  }
143 
144  /**
145  * 获取当前音频播放进度
146  *
147  * @return 当前播放进度
148  */
149  public long getCurrentPosition() {
150  if (mPlayer != null) {
151  try {
152  return mPlayer.getCurrentPosition();
153  } catch (Throwable e) {
154  e.printStackTrace();
155  NimLog.e(TAG, "getCurrentPosition error", e);
156  return 0;
157  }
158  } else {
159  return 0;
160  }
161  }
162 
163  /**
164  * 让播放器跳转到指定位置继续播放
165  *
166  * @param msec 指定播放位置,单位为毫秒
167  */
168  public void seekTo(int msec) {
169  try {
170  mPlayer.seekTo(msec);
171  } catch (Throwable e) {
172  e.printStackTrace();
173  NimLog.e(TAG, "seekTo error", e);
174  }
175  }
176 
177  private void setVolume(float leftVolume, float rightVolume) {
178  if (mPlayer == null) {
179  return;
180  }
181  try {
182  mPlayer.setVolume(leftVolume, rightVolume);
183  } catch (Throwable e) {
184  e.printStackTrace();
185  NimLog.e(TAG, "setVolume error", e);
186  }
187  }
188 
189  private void startPlay() {
190  NimLog.d(TAG, "start() called");
191 
192  endPlay();
193 
194  startInner();
195  }
196 
197  private void endPlay() {
198  audioManager.abandonAudioFocus(onAudioFocusChangeListener);
199 
200  if (mPlayer != null) {
201  try {
202  mPlayer.stop();
203  } catch (Throwable e) {
204  e.printStackTrace();
205  NimLog.e(TAG, "endPlay error", e);
206  }
207  try {
208  mPlayer.release();
209  } catch (Throwable e) {
210  e.printStackTrace();
211  NimLog.e(TAG, "endPlay error", e);
212  }
213  mPlayer = null;
214  mHandler.removeMessages(WHAT_COUNT_PLAY);
215  }
216  }
217 
218  private Handler mHandler = new Handler() {
219  @Override
220  public void handleMessage(Message msg) {
221  switch (msg.what) {
222  case WHAT_COUNT_PLAY:
223  try {
224  if (mListener != null) {
225  mListener.onPlaying(mPlayer.getCurrentPosition());
226  }
227  } catch (Throwable e) {
228  e.printStackTrace();
229  NimLog.e(TAG, " error", e);
230  }
231  sendEmptyMessageDelayed(WHAT_COUNT_PLAY, mIntervalTime);
232  break;
233  case WHAT_DECODE_FAILED: {
234  //ToastUtil.showToast(mContext, "语音播放失败");
235  NimLog.e(TAG, "convert() error: " + mAudioFile);
236  }
237  break;
238  case WHAT_DECODE_SUCCEED:
239  startInner();
240  break;
241  }
242  }
243  };
244 
245 
246  private void startInner() {
247  mPlayer = new MediaPlayer();
248  try {
249  mPlayer.setLooping(false);
250  mPlayer.setAudioStreamType(audioStreamType);
251 
252  if (audioStreamType == AudioManager.STREAM_MUSIC) {
253  audioManager.setSpeakerphoneOn(true);
254  } else {
255  audioManager.setSpeakerphoneOn(false);
256  }
257 
258  audioManager.requestAudioFocus(
259  onAudioFocusChangeListener,
260  audioStreamType,
261  AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
262 
263  mPlayer.setOnPreparedListener(new OnPreparedListener() {
264  @Override
265  public void onPrepared(MediaPlayer mp) {
266  NimLog.d(TAG, "player:onPrepared");
267  mHandler.sendEmptyMessage(WHAT_COUNT_PLAY);
268  if (mListener != null) {
269  mListener.onPrepared();
270  }
271  }
272  });
273 
274  mPlayer.setOnCompletionListener(new OnCompletionListener() {
275  @Override
276  public void onCompletion(MediaPlayer mp) {
277  NimLog.d(TAG, "player:onCompletion");
278  endPlay();
279  if (mListener != null) {
280  mListener.onCompletion();
281  }
282  }
283  });
284 
285  mPlayer.setOnErrorListener(new OnErrorListener() {
286  @Override
287  public boolean onError(MediaPlayer mp, int what, int extra) {
288  NimLog.e(TAG, String.format("player:onOnError what:%d extra:%d", what, extra));
289  endPlay();
290  if (mListener != null) {
291  mListener.onError(String.format("OnErrorListener what:%d extra:%d", what, extra));
292  }
293  return true;
294  }
295  });
296 
297  if (mAudioFile != null) {
298  mPlayer.setDataSource(mAudioFile);
299  } else {
300  if (mListener != null) {
301  mListener.onError("no datasource");
302  }
303  return;
304  }
305 
306  mPlayer.prepare();
307  mPlayer.start();
308 
309  NimLog.d(TAG, "player:start ok---->" + mAudioFile);
310  } catch (Throwable e) {
311  e.printStackTrace();
312  NimLog.e(TAG, "player:onOnError Exception\n" + e.toString());
313  endPlay();
314  if (mListener != null) {
315  mListener.onError("Exception\n" + e.toString());
316  }
317  }
318  }
319 
320  private void deleteOnExit() {
321  File converted = new File(mAudioFile);
322  if (converted.exists()) {
323  converted.deleteOnExit();
324  }
325  }
326 
327  OnAudioFocusChangeListener onAudioFocusChangeListener = new OnAudioFocusChangeListener() {
328 
329  @Override
330  public void onAudioFocusChange(int focusChange) {
331  switch (focusChange) {
332  case AudioManager.AUDIOFOCUS_GAIN:
333  // 获得音频焦点
334  if (isPlaying()) {
335  setVolume(1.0f, 1.0f);
336  }
337  break;
338 
339  case AudioManager.AUDIOFOCUS_LOSS:
340  // 长久的失去音频焦点,释放MediaPlayer
341  stop();
342  break;
343 
344  case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
345  // 展示失去音频焦点,暂停播放等待重新获得音频焦点
346  stop();
347  break;
348  case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
349  // 失去音频焦点,无需停止播放,降低声音即可
350  if (isPlaying()) {
351  setVolume(0.1f, 0.1f);
352  }
353  break;
354  }
355  }
356  };
357 }
void start(int audioStreamType)
开始播放
void onPlaying(long curPosition)
播放过程
long getDuration()
获取音频持续时间长度
AudioPlayer(Context context, String audioFile, OnPlayListener listener)
音频播放器构造函数
void setOnPlayListener(OnPlayListener listener)
设置播放监听
void onPrepared()
文件解码完成,准备播放
void seekTo(int msec)
让播放器跳转到指定位置继续播放
long getCurrentPosition()
获取当前音频播放进度
AudioPlayer(Context context)
音频播放器构造函数
void setDataSource(String audioFile)
设置音频来源
和AudioRecorder对应音频播放器。 AudioRecorder的录音格式可以是aac,但在低版本系统上,MediaPlayer是不...
boolean isPlaying()
查询是否正在播放