Android 控制车载蓝牙播放音乐详解流程

需求:手机端音乐暂停和播放状态从服务端告诉客户端、设备端实现暂停、播放、上一首、下一首等功能
代码路径:

packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
packages/apps/Bluetooth/src/com/android/bluetooth/a2dpsink/A2dpSinkService.java
packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java
packages/apps/Bluetooth/jni/com_android_bluetooth_avrcp_controller.cpp

一、蓝牙音乐播放状态

1、在AvrcpControllerService.java文件中onPlayStatusChanged()方法就是音乐播放状态改变,该方法是由JNI层中com_android_bluetooth_avrcp_controller.cpp中调用java层的

private synchronized void onPlayStatusChanged(byte[] address, byte playStatus) {
    if (DBG) {
        Log.d(TAG, "onPlayStatusChanged " + playStatus);
    }
    int playbackState = PlaybackState.STATE_NONE;
    switch (playStatus) {
        case JNI_PLAY_STATUS_STOPPED:
            playbackState = PlaybackState.STATE_STOPPED;
            break;
        case JNI_PLAY_STATUS_PLAYING:
            playbackState = PlaybackState.STATE_PLAYING;
            break;
        case JNI_PLAY_STATUS_PAUSED:
            playbackState = PlaybackState.STATE_PAUSED;
            break;
        case JNI_PLAY_STATUS_FWD_SEEK:
            playbackState = PlaybackState.STATE_FAST_FORWARDING;
            break;
        case JNI_PLAY_STATUS_REV_SEEK:
            playbackState = PlaybackState.STATE_REWINDING;
            break;
        default:
            playbackState = PlaybackState.STATE_NONE;
    }
    BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
    AvrcpControllerStateMachine stateMachine = getStateMachine(device);
    if (stateMachine != null) {
        stateMachine.sendMessage(
                AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED, playbackState);
    }
}

2、在AvrcpControllerStateMachine.java文件中Connected类中

MESSAGE_PROCESS_PLAY_STATUS_CHANGED消息就是处理播放状态的,然后通过广播方式把该状态发送出去

case MESSAGE_PROCESS_PLAY_STATUS_CHANGED:
    if (SystemProperties.get("persist.ivi.feature", "0").equals("1")) {
        A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();
        Log.d(TAG, "the state: " + msg.arg1);
        if (a2dpSinkService != null && msg.arg1 != preAudioStatus) {
            preAudioStatus = msg.arg1;
            Log.d(TAG, "preAudioStatus: " + msg.arg1);
            if (msg.arg1 == PlaybackState.STATE_PLAYING) {
                //播放
                    a2dpSinkService.informPlayState(mDevice, true);
            } else if (msg.arg1 == PlaybackState.STATE_PAUSED) {
                //暂停
                    a2dpSinkService.informPlayState(mDevice, false);
            }
        }
    }
    Intent intent = new Intent("zqc.bluetooth.PLAY_STATUS_CHANGED");
intent.putExtra("zqc.bluetooth.PLAYBACK", msg.arg1);
mService.sendBroadcast(intent);
    mAddressedPlayer.setPlayStatus(msg.arg1);
    BluetoothMediaBrowserService.notifyChanged(mAddressedPlayer.getPlaybackState());
    if (mAddressedPlayer.getPlaybackState().getState()
            == PlaybackState.STATE_PLAYING
            && A2dpSinkService.getFocusState() == AudioManager.AUDIOFOCUS_NONE
            && !shouldRequestFocus()) {
        sendMessage(MSG_AVRCP_PASSTHRU,
                AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);
    }
    return true;

二、蓝牙音乐中怎么获取音乐信息

1、在AvrcpControllerService.java文件中onTrackChanged()方法中是获取JNI层上报的音乐信息,该方法是由JNI层中com_android_bluetooth_avrcp_controller.cpp中调用java层的

private synchronized void onTrackChanged(byte[] address, byte numAttributes, int[] attributes,
        String[] attribVals) {
    if (DBG) {
        Log.d(TAG, "onTrackChanged");
    }

    BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
    AvrcpControllerStateMachine stateMachine = getStateMachine(device);
    //该方法就是把蓝牙音乐的信息传递给java层
    getElementAttrRsp(attributes,attribVals,numAttributes);
    if (stateMachine != null) {
        stateMachine.sendMessage(AvrcpControllerStateMachine.MESSAGE_PROCESS_TRACK_CHANGED,
                TrackInfo.getMetadata(attributes, attribVals));
    }
}

2、在AvrcpControllerService.java文件中getElementAttrRsp()中,然后通过该方法中通过广播告诉出去

private void getElementAttrRsp(int[] attr_id,String[] textArray,byte num_attr){
    String artist = null;
    String trackTitle = null;
    String album = null;
    for (int i = 0; i < num_attr; i++){
        switch (attr_id[i]) {
            case JNI_MEDIA_ATTR_ID_TITLE:
                trackTitle = textArray[i];
                if (trackTitle == null){
                    trackTitle = "Unknown";
                }
                break;
            case JNI_MEDIA_ATTR_ID_ARTIST:
                artist = textArray[i];
                if (artist == null){
                    artist = "Unknown";
                }
                break;
            case JNI_MEDIA_ATTR_ID_ALBUM:
                album = textArray[i];
                if (album == null){
                    album = "Unknown";
                }
                break;
        }
    }
    Intent intent = new Intent("com.android.getelementattrrsp");
    intent.putExtra("artist", artist);
    intent.putExtra("trackTitle",trackTitle);
    intent.putExtra("album",album);
    Log.d(TAG,"getElementAttrRsp,artist: " + artist + ",trackTitle: " + trackTitle + ",album: " + album);
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
    sendBroadcast(intent, ProfileService.BLUETOOTH_PERM);
}

三、设备蓝牙音乐中上一首、下一首、暂停功能控制手机端

1、在AvrcpControllerService.java文件中sendPassThroughCmd()方法来控制暂停、播放、上一首、下一首等功能

public synchronized void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {
    Log.v(TAG, "sendPassThroughCmd keyCode: " + keyCode + " keyState: " + keyState);
    if (device == null) {
        Log.e(TAG, "sendPassThroughCmd Device is null");
        return;
    }

    AvrcpControllerStateMachine stateMachine = getStateMachine(device);
    if (stateMachine != null) {
        stateMachine.sendMessage(AvrcpControllerStateMachine.MESSAGE_SEND_PASS_THROUGH_CMD,
            keyCode, keyState, device);
    }
}

2、在AvrcpControllerStateMachine.java文件中MESSAGE_SEND_PASS_THROUGH_CMD变量中通过JNI层来实现功能

case MESSAGE_SEND_PASS_THROUGH_CMD:
    BluetoothDevice device = (BluetoothDevice) msg.obj;
    mService.sendPassThroughCommandNative(Utils.getByteAddress(device), msg.arg1,
                    msg.arg2);
    return true;

到此这篇关于Android 控制车载蓝牙播放音乐详解流程的文章就介绍到这了,更多相关Android 控制车载蓝牙 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android实现蓝牙(BlueTooth)设备检测连接

    无论是WIFI还是4G网络,建立网络连接后都是访问互联网资源,并不能直接访问局域网资源.比如两个人在一起,A要把手机上的视频传给B,通常情况是打开手机QQ,通过QQ传送文件给对方.不过上传视频很耗流量,如果现场没有可用的WIFI,手机的数据流量又不足,那又该怎么办呢?为了解决这种邻近传输文件的问题,蓝牙技术应运而生.蓝牙技术是一种无线技术标准,可实现设备之间的短距离数据交换. Android为蓝牙技术提供了4个工具类,分别是蓝牙适配器BluetoothAdapter.蓝牙设备BluetoothD

  • Android 获取蓝牙Mac地址的正确方法

    android 从6.0开始,通过BluetoothAdapter.getDefaultAdapter().getAddress()获取的地址是一个固定值02:00:00:00:00:00.6.0已经对蓝牙Wi-Fi的MAC地址做了隐藏. 以下方法能正确的获取android自带蓝牙的Mac地址: 1.添加net.vidageek:mirror:1.6.1 2.实现过程 本人也尝试过其他方法获取,比如从cat /sys/class/net/wlan0/address 或者/sys/class/ne

  • android实现手机与单片机蓝牙模块通信

    本文实例为大家分享了android实现手机与单片机蓝牙模块通信的具体代码,供大家参考,具体内容如下 我是参考原博客的内容去写的,由于原博客写的不全,少了关键的几个类,然后我就凭借自己扎实的功底补出来了,现在蓝牙工作正常,能发能收!在看这边文章之前你要先了解一下蓝牙的工作状态,我的代码里面可能解释的不是很详细,但是我自己是能看懂的! package com.example.fsl.bluetooth; import android.app.Activity; import android.blue

  • Android如何实现蓝牙配对连接功能

    目录 本文适用的范围 准备 搜索 配对 连接 坑坑坑 本文适用的范围 Android蓝牙部分是很复杂的,也涉及很多名词和功能.本文介绍的配对连接方法适用于一般的蓝牙耳机.音响等,并不是连接蓝牙 BLE 或者想用蓝牙来进行 Socket 通信的. 先来介绍几种名称: Profile: Bluetooth 的一个很重要特性,就是所有的 Bluetooth 产品都无须实现全部的 Bluetooth 规范.为了更容易的保持 Bluetooth 设备之间的兼容,Bluetooth 规范中定义了 Profi

  • android蓝牙控制PC端代码分享

    引言 在安卓端通过蓝牙发送指令到PC端,java程序接收指令,并执行相应的动作.其中指令格式有所规范,PC端的java程序通过robot库进行操作 代码 控制类remotePC.java import java.awt.AWTException; import java.awt.Dimension; import java.awt.Robot; import java.awt.Toolkit; import java.awt.event.InputEvent; import java.awt.e

  • Android获取蓝牙设备列表的方法

    最近换了一家公司,主要内容是做关于移动端室内定位的相关sdk,刚进来的时候信心满满,誓要干出一番天地!!!结果进来快一个多月了,根本没轮到我施展拳脚,给我搁置在一旁自己弄自己的.行吧,既然是做室内定位的话那无非就是(gps,蓝牙,wifi等)这些技术来实现嘛,然后我们就可以有本篇的切入点了: android如何获取蓝牙设备了? 我们一步一步来分析,首先蓝牙属于一种短距离的无线通信技术,那作为我们android系统是否对此有过封装了?答案那肯定是有了! BluetoothAdapter andro

  • Android 控制车载蓝牙播放音乐详解流程

    需求:手机端音乐暂停和播放状态从服务端告诉客户端.设备端实现暂停.播放.上一首.下一首等功能 代码路径: packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java pack

  • Android Canvas和Bitmap结合绘图详解流程

    目录 Rect/RectF Matrix Canvas Bitmap Rect/RectF 存储四个值的矩形类:左侧.顶部.右侧和底部.可用于直接在画布上绘制或仅用于存储要绘制的对象的大小.Rect和RectF类之间的区别在于 RectF 存储浮点值,而Rect类存储整数. private static Bitmap createDrawableBitmap(Drawable drawable) { int width = drawable.getIntrinsicWidth(); int he

  • Android 美食大转盘详解流程

    目录 效果视频 前言 美食大转盘 初始化SurfaceView 测量 绘制 绘制盘块 开始旋转转盘 停止旋转转盘 自定义转盘等份 控件引用 沉浸式体验 效果图 Reveal Animator 效果视频 自定义转盘代码 XML布局代码 Activity代码 代码下载地址 效果视频 前言 你还在为明天吃什么而烦恼嘛 美食大赏帮你解决选择困难症 帮你做出最佳的选择 做吃货,我们是认真的 美食大转盘 本示例使用SurfaceView绘制而成,接下来逐步分析, 文末会贴出全部代码``文末会贴出全部代码``

  • Python实现多功能音乐播放器详解

    目录 前言 准备工作 知识点和所需模块 环境 完整代码 效果展示 导入模块 界面 按钮 功能 创建一个文件目录 音乐读取功能 显示已加载的音乐 播放音乐 停止播放 下一首 上一首 音量控制 关闭窗口 前言 就是用Python做一个简易的音乐播放器,废话不多说,咱们直接开干 当然,今天做这个肯定不是最简单的,最简单的音乐播放器,9行代码足以 import time import pygame file = r'歌曲路径' pygame.mixer.init() print('正在播放',file)

  • React模仿网易云音乐实现一个音乐项目详解流程

    目录 一.项目功能说明 二.最终效果 三.文件目录结构说明 四.项目技术栈 五.核心技术 六.遇到的问题 七.github链接 一.项目功能说明 暂停.播放歌曲 切换上一首.下一首歌曲 拖动进度条改变播放进度 随机播放.循环播放.单曲循环 实时展示歌词 切换不同分类的歌单.歌手.电台 实现推荐.排行榜.歌单.主播电台.歌手.新碟上架板块的展示 二.最终效果 首页: 排行榜: 歌单: 主播电台: 歌手: 新碟上架: 三.文件目录结构说明 assets:存放共用的css.font图标.image c

  • C语言流程控制之switch语句详解

    switch语句结构 switch(表达式) { case 判断值1; 语句组1: break; case 判断值2: 语句组2: break; case 判断值3: 语句组3: break; -- case 判断值n: 语句组n: break; default: 语句组n+1: break; } 表达式是选择条件,可以是单个变量也可以是组合的表达式,其最终的结果必须是一整数值,{}内的所有内容是switch语句的主体,内含多个case分支,判断值必须是一常量,case分支根据判断值标识条件选择

  • Android实现MVVM架构数据刷新详解流程

    目录 效果图 示例结构图 代码解析 导入dataBinding 实体类 xml视图 VM 绑定视图与数据层 效果图 示例结构图 代码解析 导入dataBinding dataBinding{ enabled = true } 实体类 继承BaseObservable public class Sensor extends BaseObservable 为字段添加@Bindable @Bindable public String getTmpValue() { return tmpValue; }

  • Android usb设备权限查询及自动获取详解流程

    看到当上面的对话框弹出时,可以使用命令查看顶层的活动窗口 adb shell dumpsys window | findstr mCurrentFocus mCurrentFocus=Window{41ab0ee0 u0 com.android.systemui/com.android.systemui.usb.UsbPermissionActivity} 这就是应用的位置,当然我们也可以是用grep命令来查找这个对话框的.xml文件,进入android源码然后输入命令: grep '默认情况下

  • Android实现动态添加数据与堆叠折线图详解流程

    目录 效果视频 引用 描述 导包 代码分析 初始化 动态添加数据 温度数据 湿度数据 光照数据 动态添加X轴时间值 初始化 自动刷新时间实现 尾言 效果视频 引用 描述 本示例采用的是非常.非常.非常好用的一款第三方SDK--helloCharts 传送门 导包 第一步 :导入maven maven { url 'https://jitpack.io' } 第二步:导入依赖 implementation 'com.github.lecho:hellocharts-library:1.5.8@aa

  • Android MVVM架构实现RecyclerView列表详解流程

    目录 效果图 导入引用 导入Recyclerview依赖 导入dataBinding引用 代码解析 建立实体类 建立RecyclerView子项 适配器 建立适配器 设置子项点击事件 adapter全部代码 建立VM层 子项点击事件的使用 VM层代码 数据与视图交互 效果图 导入引用 导入Recyclerview依赖 implementation 'androidx.recyclerview:recyclerview:1.1.0' 导入dataBinding引用 dataBinding { en

随机推荐