安卓从4.3就已经支持蓝牙显示歌词了,但是需要客户端和服务端同时做处理,客户端将歌词通过avrcp协议携带到服务端,服务端只要按照蓝牙规范解析就可以了,关于蓝牙协议大家可以自行去看,这里就不具体说,直接看代码是如何实现的吧
1.系统服务端如何做的
packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink/mbs/A2dpMediaBrowserService
在A2dpMediaBrowserService.java中,看看系统蓝牙是这么解析出歌词的
private void msgTrack(PlaybackState pb, MediaMetadata mmd) {
Log.d(TAG, "msgTrack: playback: " + pb + " mmd: " + mmd);
// Log the current track position/content.
MediaController controller = mSession.getController();
PlaybackState prevPS = controller.getPlaybackState();
MediaMetadata prevMM = controller.getMetadata();
if (prevPS != null) {
Log.d(TAG, "prevPS " + prevPS);
}
if (prevMM != null) {
String title = prevMM.getString(MediaMetadata.METADATA_KEY_TITLE);
long trackLen = prevMM.getLong(MediaMetadata.METADATA_KEY_DURATION);
Log.d(TAG, "prev MM title " + title + " track len " + trackLen);
}
if (mmd != null) {
Log.d(TAG, "msgTrack() mmd " + mmd.getDescription());
mSession.setMetadata(mmd);
}
if (pb != null) {
Log.d(TAG, "msgTrack() playbackstate " + pb);
PlaybackState.Builder pbb = new PlaybackState.Builder(pb);
pb = pbb.setActions(mTransportControlFlags).build();
mSession.setPlaybackState(pb);
}
}
我们可以看到,MediaMetadata prevMM = controller.getMetadata();通过prevMM这个对象拿到歌曲信息的,这儿的String title = prevMM.getString(MediaMetadata.METADATA_KEY_TITLE);这儿的title其实打印出来的就是歌词,当然,prevMM里面不仅仅携带有歌词,还有歌名,艺术家,专辑等信息,我们只要解析MediaMetadata对应的不同标签就可以获取到,下面是MediaMetadata所有的标签
String title = prevMM.getString(MediaMetadata.METADATA_KEY_TITLE;
String artist = prevMM.getString(MediaMetadata.METADATA_KEY_ARTIST;
String album = prevMM.getString(MediaMetadata.METADATA_KEY_ALBUM;
String title = prevMM.getString(MediaMetadata.METADATA_KEY_GENRE;
String title = prevMM.getString(MediaMetadata.METADATA_KEY_TRACK_NUMBER;
String title = prevMM.getString(MediaMetadata.METADATA_KEY_NUM_TRACKS;
String title = prevMM.getString(MediaMetadata.METADATA_KEY_DURATION;
String title = prevMM.getString(MediaMetadata.METADATA_KEY_MEDIA_ID;
不过我们只要歌词,歌名,艺术家就可以了,下面教大家一种比较简易的方法就是在系统添加一个广播,将这些信息携带出去,然后客户端直接接收广播拿到对应的信息就可以显示了,具体操作如下:
if (prevMM != null) {
String title = prevMM.getString(MediaMetadata.METADATA_KEY_TITLE);
String AlbumTitle = prevMM.getString(MediaMetadata.METADATA_KEY_ALBUM);
String artist = prevMM.getString(MediaMetadata.METADATA_KEY_ARTIST);
long trackLen = prevMM.getLong(MediaMetadata.METADATA_KEY_DURATION);
Intent intent = new Intent();
intent.setAction("action");
intent.putExtra("title",title);
intent.putExtra("AlbumTitle",AlbumTitle);
intent.putExtra("artist",artist);
sendBroadcast(intent);
Log.d(TAG, "prev MM title " + title + " track len " + trackLen);
Log.d(TAG,"AlbumTitle:"+AlbumTitle);
}
这样我们已经把要的东西已经拿出来了了,下面我们只要在应用端显示就可以了,接下来我们看看服务端怎么显示的
BroadcastReceiver mreceive = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if ("com.focconn.mateble".equals(action)){ String lyric = intent.getStringExtra("title"); String mAlbumTitle = intent.getStringExtra("AlbumTitle"); String mArtist = intent.getStringExtra("artist"); Log.i("say","歌词:"+lyric+" 歌名:"+mAlbumTitle); if (mAlbumTitle.length()==0||lyric.equals(mAlbumTitle)){ textView.setText("暂无歌词"); }else { textView.setText(lyric); } titlte.setText(mAlbumTitle); artist.setText(mArtist); } } };
我们只要注册一个广播就可以拿到歌词和歌名了,是不是很简单。这只是接收,那么下面我们看看音乐播放器是怎么把这些信息发过来把。当然如歌不修改系统我们也能做,我们只要接收到BluetoothAvrcpController.ACTION_TRACK_EVENT.equals(action)这个广播如何显示歌词,也是可以的,但是这个广播时隐藏的,大家要么通过反射或者导入framework.jar都可以,不过修改系统是最方便的,但是缺点是,在播放时会不停的发送广播。
2.客户端如何发送歌词的
客户端是同过avrcp将歌曲信息传送过去的,具体的我们来看播放器的代码:
public void put(){ mSession = new MediaSession(getApplicationContext(), "remusic"); Log.i("Music","mIsSupposedToBePlaying:"+mIsSupposedToBePlaying+"STATE_PLAYING:"+PlaybackState.STATE_PLAYING +" PlaybackState.ACTION_PLAY:"+PlaybackState.ACTION_PLAY); int playState = mIsSupposedToBePlaying ? PlaybackState.STATE_PLAYING : PlaybackState.STATE_PAUSED; mSession.setPlaybackState(new PlaybackState.Builder() .setState(playState, 1, 1.0f) .setActions(PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PAUSE | PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_SKIP_TO_NEXT | PlaybackState.ACTION_SKIP_TO_PREVIOUS) .build()); Bitmap albumArt = null; if (albumArt != null) { Bitmap.Config config = albumArt.getConfig(); if (config == null) { config = Bitmap.Config.ARGB_8888; } albumArt = albumArt.copy(config, false); } Log.i("Music","updateMediaSession"); mSession.setMetadata(new MediaMetadata.Builder() .putString(MediaMetadata.METADATA_KEY_ARTIST, artist) .putString(MediaMetadata.METADATA_KEY_ALBUM, album) .putString(MediaMetadata.METADATA_KEY_TITLE, title) .build()); mSession.setActive(true); }
这儿只是最简易的发送,我是通过手动点击发送测试的,具体的大家要根据播放音乐时获取到的歌词来调用,这样歌词就可以和音乐同步显示了。现在音乐客户端这一块,QQ音乐已经支持了歌词发送,也就是说只要在服务端做处理就可以了,而酷狗,网易等只有歌名和艺术家,不知道以后会不会有支持。到了这儿,客户端和服务端实现原理都讲清楚了,大家有需要的可以了解了解。我也参考了一些网上资料和看了一些系统源码写的这个,如果有什么问题欢迎指教。