说明:播放器核心采用IjkPlayer(bilibili开源库)、so库采用GsyVideoPlayer(IjkPlayer so 默认不支持https 格式!)
Demo:地址 https://download.csdn.net/download/BirdEatBug/19363714 无需积分 demo 需要关注 MediaPlayerActivity与MediaService两个类即可;
播放器代码:
package com.kuaige.player.player;
import android.media.AudioManager;
import java.io.IOException;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
public class IjkAudioPlayer {
private IjkMediaPlayer ijkMediaPlayer;
public IjkMediaPlayer getPlayer() {
return ijkMediaPlayer;
}
public void init() {
if (ijkMediaPlayer == null) {
ijkMediaPlayer = new IjkMediaPlayer();
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER,"soundtouch",0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT,"analyzemaxduration",50L);
/* ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT,"analyzeduration",1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT,"probesize",1024*10);*/
}
ijkMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
public void setPathAndPrepare(String uri) {
try {
ijkMediaPlayer.setDataSource(uri);
ijkMediaPlayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
public void start() {
if (ijkMediaPlayer != null) {
ijkMediaPlayer.start();
}
}
public void pause(){
if (ijkMediaPlayer != null) {
ijkMediaPlayer.pause();
}
}
public void stop(){
if (ijkMediaPlayer != null) {
ijkMediaPlayer.stop();
}
}
/**
* 耗时
*/
public void reset(){
if (ijkMediaPlayer != null) {
ijkMediaPlayer.reset();
}
}
public void release() {
if (ijkMediaPlayer != null) {
ijkMediaPlayer.reset();
ijkMediaPlayer.release();
ijkMediaPlayer = null;
}
}
}
Service代码:
package com.kuaige.player.player;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.kuaige.player.R;
import com.kuaige.player.RadioAudioEvent;
import com.kuaige.player.utils.AudioFocusManager;
import org.greenrobot.eventbus.EventBus;
import tv.danmaku.ijk.media.player.IMediaPlayer;
public class MediaService extends Service implements IMediaPlayer.OnErrorListener, IMediaPlayer.OnPreparedListener {
//ijk播放器
private IjkAudioPlayer ijkAudioPlayer;
private AudioFocusManager audioFocusManager = new AudioFocusManager();
private boolean isPrepared;
private boolean isStop;
private boolean isPause;
//是否播放过音乐、防止多次启动时setPathAndPrepare 异常(无法捕获)
private boolean isInit;
private static final String PLAY_URI = "play_uri";
private static final String PLAY = "play";
private static final String CONTINUE_PLAY = "continue_play";
private static final String PAUSE = "pause";
private static final String STOP = "stop";
public static final String STOP_PLAY_SERVICE = "stop_play_service";
public static final int RELEASE = 101;
//记录播放uri
private String oldUri = "";
private Handler handler = new Handler();
public static void startPlay(Context context, String uri) {
context.startService(new Intent(context, MediaService.class).putExtra(PLAY_URI, uri).setAction(PLAY));
}
//继续播放、若已发生暂停
public static void continuePlay(Context context) {
context.startService(new Intent(context, MediaService.class).setAction(CONTINUE_PLAY));
}
public static void pausePlay(Context context) {
context.startService(new Intent(context, MediaService.class).setAction(PAUSE));
}
public static void stopPlay(Context context) {
context.startService(new Intent(context, MediaService.class).setAction(STOP));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
if (ijkAudioPlayer == null) {
ijkAudioPlayer = new IjkAudioPlayer();
ijkAudioPlayer.init();
ijkAudioPlayer.getPlayer().setOnErrorListener(this);
ijkAudioPlayer.getPlayer().setOnPreparedListener(this);
}
initAudioListener();
//常驻通知栏
createMusicNotification(this);
}
private void initAudioListener() {
/* //请求语音播放焦点
int requestCode = audioFocusManager.requestTheAudioFocus(new AudioFocusManager.AudioListener() {
@Override
public void start() {
Log.d("----------tag", "start");
}
@Override
public void pause() {
Log.d("----------tag", "pause");
}
}, this);
if(requestCode == AudioManager.AUDIOFOCUS_REQUEST_GRANTED){
// playVoice();//播放音频的方法
Log.d("----------tag", "AUDIOFOCUS_REQUEST_GRANTED");
}*/
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction() != null) {
switch (intent.getAction()) {
case CONTINUE_PLAY:
if (!TextUtils.isEmpty(oldUri)) {
if (isPrepared && isPause) {
ijkAudioPlayer.start();
isPause = false;
}
}
break;
case PLAY:
String uri = intent.getStringExtra(PLAY_URI);
boolean sameUri = oldUri.equals(uri);
oldUri = uri;
//是否是暂停
if (isPrepared && isPause && sameUri) {
ijkAudioPlayer.start();
isPause = false;
EventBus.getDefault().post(new RadioAudioEvent(true));
//当停止播放时
} else if (isStop || ijkAudioPlayer.getPlayer().isPlaying() || !sameUri) {
ijkAudioPlayer.stop();
ijkAudioPlayer.reset();
ijkAudioPlayer.setPathAndPrepare(uri);
} else {
if (!isInit) {
ijkAudioPlayer.setPathAndPrepare(uri);
}
}
// mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
break;
case PAUSE:
if (ijkAudioPlayer.getPlayer().isPlaying()) {
ijkAudioPlayer.pause();
isPause = true;
}
break;
case STOP:
if (ijkAudioPlayer.getPlayer().isPlaying()) {
ijkAudioPlayer.stop();
isPrepared = false;
isStop = true;
}
break;
case STOP_PLAY_SERVICE:
stopSelf();
break;
}
}
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
ijkAudioPlayer.stop();
ijkAudioPlayer.release();
isPrepared = false;
}
@Override
public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
isPrepared = false;
isStop = true;
Toast.makeText(this, "出错了、请重试!", Toast.LENGTH_SHORT).show();
EventBus.getDefault().post(new RadioAudioEvent(true));
return false;
}
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
isInit = true;
isPrepared = true;
isStop = false;
iMediaPlayer.start();
isPause = false;
//通知 主model
EventBus.getDefault().post(new RadioAudioEvent(true));
}
public void createMusicNotification(Context context) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("qiqile", "齐齐乐渠道",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "qiqile");
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setOngoing(true);//代表是常驻的,主要是配合服务
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.notify_custom);
//暂停或者重新播放
Intent stopIntent = new Intent(context, MediaService.class);
stopIntent.setAction(STOP_PLAY_SERVICE);
PendingIntent startOrPauseP = PendingIntent.getService(context, MediaService.RELEASE, stopIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.ivStop, startOrPauseP);
builder.setContent(remoteViews);
Notification notification = builder.build();
startForeground(0x11, notification);
}
}
备注:状态控制有些啰嗦、可自行修改!