1.框架预览
2.用法
2.1参考链接:
MediaSession 简单使用
2.2 服务端要实现MediaBrowserService;
主要实现的功能:
mPlaybackState = new PlaybackStateCompat.Builder()
.setState(PlaybackStateCompat.STATE_NONE, currentPostion, 1.0f)
.setActions(getAvailableActions(PlaybackStateCompat.STATE_NONE))
.build();
//初始化,第一个参数为context,第二个参数为String类型tag,这里就设置为类名了
mediaSession = new MediaSessionCompat(this, "MediaService");
//设置token
setSessionToken(mediaSession.getSessionToken());
//设置callback,这里的callback就是客户端对服务指令到达处
mediaSession.setCallback(mCallback);
在MediaSessionCompat.Callback 中实现具体的播放与控制逻辑
//mediaSession设置的callback,也是客户端控制指令所到达处
private final MediaSessionCompat.Callback mCallback = new MediaSessionCompat.Callback() {
//重写的方法都是选择性重写的,不完全列列举,具体可以查询文章末尾表格
@Override
public void onPlay() {
super.onPlay();
Log.d(TAG, "onPlay: isPrepare = " + isPrepare);
//客户端mMediaController.getTransportControls().play()就会调用到这里,以下类推
//处理播放逻辑
//处理完成后通知客户端更新,这里就会回调给客户端的MediaController.Callback
if (null != mMediaPlayer && !isPrepare) {
handleOpenUri(MusicListData.rawToUri(MediaService.this, Objects.requireNonNull(getPlayBean()).mediaId));
} else {
handlePlay();
}
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
handlePause(true);
}
@Override
public void onSeekTo(long pos) {
super.onSeekTo(pos);
//设置到指定进度时触发
}
@Override
public void onSkipToPrevious() {
int pos = (currentPostion + mPlayBeanList.size() - 1) % mPlayBeanList.size();
Log.e(TAG, "onSkipToPrevious pos = " + pos);
handleOpenUri(MusicListData.rawToUri(MediaService.this, Objects.requireNonNull(setPlayPosition(pos)).mediaId));
}
@Override
public void onSkipToNext() {
super.onSkipToNext();
//下一首
//通知媒体信息改变
// mediaSession.setMetadata(mediaMetadata);
int pos = (currentPostion + 1) % mPlayBeanList.size();
Log.d(TAG, "onSkipToNext: pos = " + pos);
handleOpenUri(MusicListData.rawToUri(MediaService.this, Objects.requireNonNull(setPlayPosition(pos)).mediaId));
}
/**
* 响应MediaControllerCompat.getTransportControls().playFromUri
*
* @param uri uri
* @param extras extras
*/
@Override
public void onPlayFromUri(Uri uri, Bundle extras) {
Log.e(TAG, "onPlayFromUri");
int position = extras.getInt("playPosition");
setPlayPosition(position);
handleOpenUri(uri);
}
@Override
public void onCustomAction(String action, Bundle extras) {
super.onCustomAction(action, extras);
//自定义指令发送到的地方
//对应客户端 mMediaController.getTransportControls().sendCustomAction(...)
}
};
这里要注意监听音频焦点的变化。
AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focusChange) {
Log.d(TAG, "onAudioFocusChange focusChange = " + focusChange + ", before isHaveAudioFocus = " +
isHaveAudioFocus);
switch (focusChange) {
case AudioManager.AUDIOFOCUS_LOSS:
// 音源丢失
isHaveAudioFocus = false;
mCallback.onPause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// 音源短暂丢失
isHaveAudioFocus = false;
Log.d(TAG, " AUDIOFOCUS_LOSS_TRANSIENT ");
handlePause(false);
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// 降低音量
break;
case AudioManager.AUDIOFOCUS_GAIN:
// 获得音源
isHaveAudioFocus = true;
mCallback.onPlay();
break;
case AudioManager.AUDIOFOCUS_REQUEST_FAILED:
// 音源申请失败
break;
default:
break;
}
}
};
private int requestAudioFocus() {
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
isHaveAudioFocus = AudioManager.AUDIOFOCUS_REQUEST_GRANTED == result;
return result;
}
/**
* 释放焦点
*/
private void abandAudioFocus() {
int result = mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener);
isHaveAudioFocus = AudioManager.AUDIOFOCUS_REQUEST_GRANTED == result;
}
播放的同时需要把播放状态和歌曲信息 回传给客户端
private void sendPlaybackState(int state, Bundle extras) {
mPlaybackState = new PlaybackStateCompat.Builder()
.setState(state, currentPostion, 1.0f)
.setActions(getAvailableActions(state))
.setExtras(extras)
.build();
mediaSession.setPlaybackState(mPlaybackState);
}
歌曲数据需要转成对应格式
private MediaMetadataCompat buildFromLocal(Song song){
String title = song.getTitle();
String album = song.getAlbum();
String artist = song.getArtist();
int duration = song.getDuration();
String source = song.getPath();
String strId = "";
if(title != null && artist != null){
strId = title + artist;
}
String id = String.valueOf(strId.hashCode());
String albumArt = song.getAlbumObj().getAlbumArt();
return new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID,id)
.putString(SongSource.CUSTOM_METADATA_TRACK_SOURCE, source)
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI,source)
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM,album)
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST,artist)
.putString(MediaMetadataCompat.METADATA_KEY_ART_URI,albumArt)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION,duration)
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, title)
.build();
}
2.3客户端绑定MediaBrowserService.
创建MediaBrowser 客户端,连接倒对应服务器。
private MediaBrowserCompat mMediaBrowser;
mMediaBrowser = new MediaBrowserCompat(this,
new ComponentName(this, MusicService.class), mConnectionCallback, null);
private final MediaBrowserCompat.ConnectionCallback mConnectionCallback =
new MediaBrowserCompat.ConnectionCallback() {
@Override
public void onConnected() {
//说明已经连接上了
try {
connectToSession(mMediaBrowser.getSessionToken());
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
连接的callback,在成功连接时,获取 MediaController, 并注册MediaControllerCompat.Callback。
private final MediaBrowserCompat.ConnectionCallback mConnectionCallbacks = new MediaBrowserCompat.ConnectionCallback() {
@Override
public void onConnected() {
Log.d(TAG, "MediaBrowser.onConnected");
if (mMediaBrowser.isConnected()) {
String mediaId = mMediaBrowser.getRoot();
mMediaBrowser.unsubscribe(mediaId);
//之前说到订阅的方法还需要一个参数,即设置订阅回调SubscriptionCallback
//当Service获取数据后会将数据发送回来,此时会触发SubscriptionCallback.onChildrenLoaded回调
mMediaBrowser.subscribe(mediaId, browserSubscriptionCallback);
try {
MediaControllerCompat mediaController = new MediaControllerCompat(DemoActivity.this,
mMediaBrowser.getSessionToken());
MediaControllerCompat.setMediaController(DemoActivity.this, mediaController);
// mediaController = new MediaControllerCompat(DemoActivity.this, mMediaBrowser.getSessionToken());
mediaController.registerCallback(mMediaControllerCallback);
if (mediaController.getMetadata() != null) {
updatePlayMetadata(mediaController.getMetadata());
updatePlayState(mediaController.getPlaybackState());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onConnectionSuspended() {
// 连接中断回调
Log.d(TAG, "onConnectionSuspended");
}
@Override
public void onConnectionFailed() {
Log.d(TAG, "onConnectionFailed");
}
};
注册回调,监听播放状态和歌曲信息的变化。
private final MediaControllerCompat.Callback mMediaControllerCallback =
new MediaControllerCompat.Callback() {
@Override
public void onPlaybackStateChanged(@NonNull PlaybackStateCompat state) {
//这里根据播放状态的改变,本地ui做相应的改变,例如播放模式,播放、暂停,进度条等
updatePlaybackState(state);
}
@Override
public void onMetadataChanged(MediaMetadataCompat metadata) {
//歌曲的信息,例如播放时长,歌曲名称等
updateDuration(metadata);
}
@override
public void onQueueChanged(List<QueueItem> queue) {
}
};
控制服务端的播放逻辑。通过mediaController.getTransportControls() 去调用。如:
TransportControls.skipToPrevious();
TransportControls.skipToNext();
TransportControls.pause();
TransportControls.play();