写点什么

手把手教你打通车载蓝牙与手机 app 的音频信息传输 & 车载反向控制手机 app

用户头像
Android架构
关注
发布于: 2021 年 11 月 03 日

Log.d(TAG,"update PlaybackState "+mediaPlayer.getCurrentPosition());mediaSession.setPlaybackState(new PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, mediaPlayer.getCurrentPosition(), 1.0f).build());mediaSession.setMetadata(new MediaMetadata.Builder().putLong(MediaMetadata.METADATA_KEY_DURATION, mediaPlayer.getDuration()).putString(MediaMetadata.METADATA_KEY_TITLE, "你是风而我是沙"+i).putString(MediaMetadata.METADATA_KEY_ARTIST, "我是谁谁谁").build());SystemClock.sleep(500);i++;}}});

车载音频信息接收

当系统接收到音频信息变化的时候会发送两个广播:



因此我们也同样的注册这个广播以便接收音频信息。


BroadcastReceiver avrcpBroadcastReceiver = new BroadcastReceiver() {@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overridepublic void onReceive(Context context, Intent intent) {if(intent.getAction().equals(AvrcpControllerHelper.ACTION_TRACK_EVENT)){final MediaMetadata mediaMetadata = intent.getParcelableExtra(AvrcpControllerHelper.EXTRA_METADATA);final PlaybackState playbackState = intent.getParcelableExtra(AvrcpControllerHelper.EXTRA_PLAYBACK);// if(mediaMetadata == null || playbackState == null){// Log.e(TAG,"some info null ? = "+mediaMetadata+" "+playbackState);// return;// }if(mediaMetadata != null){name = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);author = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);totalTime = timeCover(+mediaMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION));}if(playbackState != null){currentTime = timeCover(playbackState.getPosition());play = playbackState.getState() == PlaybackState.STATE_PLAYING;}TextView textView = findViewById(R.id.tvPlayTime);textView.setText("开始时间"+currentTime);textView = findViewById(R.id.tvTotalTime);textView.setText("总时长"+totalTime);textView = findViewById(R.id.tvMusicInfo);textView.setText("歌名:"+name +"------------ 作者 : "+author);textView = findViewById(R.id.tvPlayToggle);textView.setText("远程播放器 "+(play?"正在播放":"未播放"));}}};


registerReceiver(avrcpBroadcastReceiver,new IntentFilter(AvrcpControllerHelper.ACTION_TRACK_EVENT));

车载蓝牙如何反向控制音频播放器

车载蓝牙要反向控制音频播放器需要借助 BluetoothAvrcpController,BluetoothAvrcpController 对普通应而言是隐藏的。如果有 framework 可以直接访问,没有的话我们可以通过反射来进行处理。BluetoothAvrcpController#sendGroupNavigationCmd 是用来反向调用音频播放器的。


同时我们为 mediaSession 设置 callback 对象


mediaSession.setCallback(new MediaSession.Callback() {


@Overridepublic void onCommand(@NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {Log.e(TAG,"onCommand");super.onCommand(command, args, cb);}


@Overridepublic boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {Log.e(TAG,"onMediaButtonEvent");Toast.makeText(BluetoothPlayerActivity.this,"我对你那么好,你居然操作我",Toast.LENGTH_SHORT).show();return super.onMediaButtonEvent(mediaButtonIntent);}});


反射 BluetoothAvrcpController 来处理相关的方法


public class AvrcpControllerHelper {private static final String TAG = AvrcpControllerHelper.class.getSimpleName();public static int AVRCP_CONTROLLER = 12;


public static final String ACTION_TRACK_EVENT = "android.bluetooth.avrcp-controller.profile.action.TRACK_EVENT";public static final String EXTRA_METADATA = "android.bluetooth.avrcp-controller.profile.extra.METADATA";public static final String EXTRA_PLAYBACK = "android.bluetooth.avrcp-controller.profile.extra.PLAYBACK";


public static void sendGroupNavigationCmd(BluetoothProfile bluetoothProfile, BluetoothDevice device, int keyCode, int keyState){if(bluetoothProfile != null){try {Method m = bluetoothProfile.getClass().getMethod("sendGroupNavigationCmd",BluetoothDevice.class,int.class,int.class);m.setAccessible(true);m.invok


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


e(bluetoothProfile,device,keyCode,keyState);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}}}


private static void fixSystemHideApi(){if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {return;}try {Method forName = Class.class.getDeclaredMethod("forName", String.class);Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);Class<?> vmRuntimeClass = (Class<?>) forName.invoke(null, "dalvik.system.VMRuntime");Method getRuntime = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null);Method setHiddenApiExemptions = (Method) getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", new Class[]{String[].class});Object sVmRuntime = getRuntime.invoke(null);setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{new String[]{"L"}});} catch (Throwable e) {Log.e("[error]", "reflect bootstrap failed:", e);}}


public static List<BluetoothDevice> getConnectedDevices(BluetoothProfile profile){if(profile == null){return null;}fixSystemHideApi();try {Method m = profile.getClass().getDeclaredMethod("getConnectedDevices");m.setAccessible(true);return (List<BluetoothDevice>) m.invoke(profile);} catch (NoSuchMethodException e) {Log.w(TAG, "No disconnect method in the " + profile.getClass().getName() +" class, ignoring request.");return null;} catch (InvocationTargetException | IllegalAccessException e) {Log.w(TAG, "Could not execute method 'disconnect' in profile " +profile.getClass().getName() + ", ignoring request.", e);return null;}}


//系统的 BluetoothAvrcp 获取不到,这里把这个拷贝出来 public static class BluetoothAvrcp {


/*


  • State flags for Passthrough commands*/public static final int PASSTHROUGH_STATE_PRESS = 0;public static final int PASSTHROUGH_STATE_RELEASE = 1;


/*


  • Operation IDs for Passthrough commands/public static final int PASSTHROUGH_ID_SELECT = 0x00; / select /public static final int PASSTHROUGH_ID_UP = 0x01; / up /public static final int PASSTHROUGH_ID_DOWN = 0x02; / down /public static final int PASSTHROUGH_ID_LEFT = 0x03; / left /public static final int PASSTHROUGH_ID_RIGHT = 0x04; / right /public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; / right-up /public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; / right-down /public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; / left-up /public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; / left-down /public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; / root menu */

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
手把手教你打通车载蓝牙与手机app的音频信息传输&车载反向控制手机app