手机app传输信息到车载

车载反向控制手机:

认识profile文件

可以这样来进行简单的理解profile标致了一种能力,他定义 了设备之间如何进行交互,比如我们跨设备调用的AVRCP是定义如何进行跨设备调用的。每一个协议多有自己的profile(要看系统有没有实现对应的功能,如果不需要可以没有对应的profile)。

音频信息如何发送给车载蓝牙

在android5.0之前的音频信息发送是通过RemoteControlClient来完成的。5.0之后是通过MediaSession来完成。

MediaSession能够进行播放器音量、按键和数据传输控制的类。一般而言一个应用程序只有一个MediaSession。

如果想要接收其它设备的调用控制需要调用 setActive(true)和setCallback(Callback)。

音频信息的发送

通过MediaSession#setMetadata(@Nullable MediaMetadata metadata)可以发送当前歌曲信息,

在MediaMetadata 定义了很多相关的key,数据发送端只需要按照对应的key添加数据即可

MediaSession#setPlaybackState(@Nullable PlaybackState state)可以发送与播放状态相关的信息。

播放器数据发送:

mediaSession = new MediaSession(BluetoothPlayerActivity.this, “test”);
mediaSession.setActive(true);
mediaSession.setMetadata(new MediaMetadata.Builder()
.putString(MediaMetadata.METADATA_KEY_TITLE, “你是风而我是沙”)
.putString(MediaMetadata.METADATA_KEY_ARTIST, “我是谁谁谁”)
.build());
Toast.makeText(BluetoothPlayerActivity.this,“已经开始执行发送信息,重置需要退出重进”,Toast.LENGTH_SHORT).show();
AppExecutors.getInstance().networkIO().execute(new Runnable() {
@Override
public void run() {
int i = 0;
while (!destroy){
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)
@Override
public 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() {

@Override
public void onCommand(@NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {
Log.e(TAG,“onCommand”);
super.onCommand(command, args, cb);
}

@Override
public 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.invoke(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”, Stri
ng.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) {
[]{String[].class});
Object sVmRuntime = getRuntime.invoke(null);
setHiddenApiExemptions.invoke(sVmRuntime, new Object[]{new String[]{“L”}});
} catch (Throwable e) {

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

  1. 物联网全栈教程--手把手教你开发一个智能浇花器(2)-GPIO 控制三色灯颜色和BSP函数实现

    大家好,我是吴彦祖,好了啦.骗你们的啦.我是Mr_Dong.下面我们正式来讲ESP8266 中GPIO的控制. 先看一下手册中GPIO对于的API函数介绍. 看完了上面介绍.我们下面写个实例加深一下印 ...

  2. 基于APP Inventor2的蓝牙智能小车控制之APP操作系统篇(20191220更新篇)

    1.整体思路 目前基于单片机的智能控制是实现建议操作功能的最直接.最有效的实现方案,这里首先是考虑再蓝牙模式下,实现控制功能,下阶段将进一步延申使用WIFI模式如何实现控制操作.整体以模块化方式实现各 ...

  3. java 注册探探账号_零基础手把手教你开发探探类社交软件Tinder

    原标题:零基础手把手教你开发探探类社交软件Tinder 目录介绍 1.关于项目App整体架构 1.1项目整体架构 1.1.1 目前项目使用架构 1.1.2 目前常见的架构 1.1.3 MVP架构优点及 ...

  4. 后端思维篇:手把手教你写一个并行调用模板

    前言 36个设计接口的锦囊中,也提到一个知识点:就是使用并行调用优化接口.所以接下来呢,就快马加鞭写第二篇:手把手教你写一个并行调用模板~ 一个串行调用的例子(App首页信息查询) Completio ...

  5. 在Airtest中如何使用无线模式控制手机

    在Airtest中如何使用无线模式控制手机 在使用Airtest超快速开发App爬虫文章的最后,我们留了一个尾巴:如何启动Airtest的无线模式,不用USB线就能控制手机? 本文将会讲到具体的做法. ...

  6. Android开发之控制手机振动(Vibrator的使用)

    Vibrator类是用于操作手机上的振动器的类,Vibrator使用很简单可以通过getSystemService(Service.VIBRATOR_SERVICE)得到Vibrator实例. Vib ...

  7. android vibrator权限,Android开发之控制手机振动(Vibrator的使用)

    Vibrator类是用于操作手机上的振动器的类,Vibrator使用很简单可以通过getSystemService(Service.VIBRATOR_SERVICE)得到Vibrator实例. Vib ...

  8. 如何恢复录音删除的录音文件_手机录音机的音频文件在哪

    手机上自带的录音功能在我们平常的工作和日常生活中都会需要用到,那么我们录音之后录音文件保存在哪个文件夹呢,下面就来介绍一下手机录音机的音频文件在哪. 手机录音机的音频文件在哪 步骤1.首先,我们打开手 ...

  9. Python控制手机,五排上分

    当你想抢王者聊天频道的皮肤碎片红包,或者想和小姐姐(小哥哥)开游戏的时候.可以使用python自动化工具,进行自动化加入开黑房间(一般小姐姐开黑会开语音,然后就会有大佬带,然后就容易上分,哈哈哈).然 ...

最新文章

  1. mysql免安装版5.7.7以后在windows上的那些操作(1)
  2. php jira,php – 为Jira的api添加附件
  3. java函数式 new_java8简单入门--函数式接口 @FunctionalInterface
  4. jpg图片使用pil的resize后_如何使用PIL调整图像大小并保持其纵横比?
  5. Linux :IO多路复用模型
  6. Celery介绍及常见错误
  7. jquery name选择器_jquery笔记
  8. 另类架构师:在国企涂肥皂水、考研被调剂、在阿里跟十八罗汉当同事……
  9. php报错怎么改,php 怎么设置报错级别 和 控制报错[转]
  10. 计算机图形学E11——B样条曲线
  11. 一起来玩AZURE SQL(一)AZURE SQL 介绍
  12. 嵌入式学习流程(参考一)
  13. 简单五子棋(单机版-C)
  14. 动态SQL 模糊查询 联表查询
  15. 告诉你喝水的14个惊人真相
  16. 【Android工具】旧手机不吃灰,变身手机行车记录仪
  17. 推荐收藏黑客APP破解常用工具集合
  18. 阳光电源中标国内单体最大光储融合项目
  19. JavaScript - 京东放大镜效果:鼠标移动查看图片放大细节
  20. Starling2.0真的适合手游开发吗

热门文章

  1. Git生成公钥、私钥以及ssh key配置
  2. Numpy删除指定行
  3. 初探 MacBook Pro 刘海屏
  4. 国内外镜像下载合集(详细最终版)
  5. RabbitMQ:消费者ACK机制、生产者消息确认
  6. 开关量无线传输-1主4从
  7. 《程序员脱发指南》--饮食篇
  8. 帮你解读身份证号码的秘密
  9. 漫画版的你,离线版AnimeGANv2初体验
  10. 2021-07-01 Leetcode题解:545,915,1647,722