Android 蓝牙实战——蓝牙音乐播放/暂停状态(二十二)

        对于蓝牙音乐的播放状态,我们首先主要处理的是 onPlayStatusChanged() 回调,这是协议栈通知 FW 层的一个回调接口。还有一个就是 getPlayBackState() 方法,这是媒体应用在初始化时未收到回调信息主动获取当前状态的方法。我们这里就来分析一下这两个状态的获取流程。

一、状态回调

1、AvrcpControllerService 

源码位置:/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerService.java

onPlayStatusChanged

        这个回调比较重要,直接接收协议栈返回的播放状态变化接口,很多 Bug 的播放状态分析都是以这个接口的状态为参考,所以记住这里打印的 LOG。

// Called by JNI on changes of play status
private synchronized void onPlayStatusChanged(byte[] address, byte playStatus) {if (DBG) {Log.d(TAG, "onPlayStatusChanged " + playStatus);}BluetoothDevice device = getAnonymousDevice(address);AvrcpControllerStateMachine stateMachine = getStateMachine(device);if (stateMachine != null) {stateMachine.sendMessage(AvrcpControllerStateMachine.MESSAGE_PROCESS_PLAY_STATUS_CHANGED,toPlaybackStateFromJni(playStatus));}
}

        这里通过 toPlaybackStateFromJni() 接口将底层返回的播放状态转化为对应数据。然后发送 MESSAGE_PROCESS_PLAY_STATUS_CHANGED 消息到协议栈进行处理。

toPlaybackStateFromJni

private int toPlaybackStateFromJni(int fromJni) {int playbackState = PlaybackStateCompat.STATE_NONE;switch (fromJni) {case JNI_PLAY_STATUS_STOPPED:playbackState = PlaybackStateCompat.STATE_STOPPED;break;case JNI_PLAY_STATUS_PLAYING:playbackState = PlaybackStateCompat.STATE_PLAYING;break;case JNI_PLAY_STATUS_PAUSED:playbackState = PlaybackStateCompat.STATE_PAUSED;break;case JNI_PLAY_STATUS_FWD_SEEK:playbackState = PlaybackStateCompat.STATE_FAST_FORWARDING;break;case JNI_PLAY_STATUS_REV_SEEK:playbackState = PlaybackStateCompat.STATE_REWINDING;break;default:playbackState = PlaybackStateCompat.STATE_NONE;}return playbackState;
}

3、AvrcpControllerStateMachine

源码位置:/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java

private AvrcpPlayer mAddressedPlayer;case MESSAGE_PROCESS_PLAY_STATUS_CHANGED:// 设置播放状态mAddressedPlayer.setPlayStatus(msg.arg1);if (!isActive()) {sendMessage(MSG_AVRCP_PASSTHRU, AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);return true;}// 通知回调播放状态PlaybackStateCompat playbackState = mAddressedPlayer.getPlaybackState();BluetoothMediaBrowserService.notifyChanged(playbackState);// 处理A2dp焦点int focusState = AudioManager.ERROR;A2dpSinkService a2dpSinkService = A2dpSinkService.getA2dpSinkService();if (a2dpSinkService != null) {focusState = a2dpSinkService.getFocusState();}if (focusState == AudioManager.ERROR) {sendMessage(MSG_AVRCP_PASSTHRU, AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);return true;}if (playbackState.getState() == PlaybackStateCompat.STATE_PLAYING && focusState == AudioManager.AUDIOFOCUS_NONE) {if (shouldRequestFocus()) {mSessionCallbacks.onPrepare();} else {sendMessage(MSG_AVRCP_PASSTHRU, AvrcpControllerService.PASS_THRU_CMD_ID_PAUSE);}}return true;
}

        这里处理 MESSAGE_PROCESS_PLAY_STATUS_CHANGED 消息,首先调用了 AvrcpPlayer 的 setPlayStatus() 方法保存播放状态,然后通过 BluetoothMediaBrowserService 继续通过回调接口返回当前状态,这个流程就与前面的播放进度回调一致了。这里我们主要关注播放状态的保存。

4、AvrcpPlayer

源码位置:/packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpPlayer.java

private PlaybackStateCompat mPlaybackStateCompat;public void setPlayStatus(int playStatus) {if (mPlayTime != PlaybackStateCompat.PLAYBACK_POSITION_UNKNOWN) {mPlayTime += mPlaySpeed * (SystemClock.elapsedRealtime() - mPlaybackStateCompat.getLastPositionUpdateTime());}mPlayStatus = playStatus;switch (mPlayStatus) {case PlaybackStateCompat.STATE_STOPPED:mPlaySpeed = 0;break;case PlaybackStateCompat.STATE_PLAYING:mPlaySpeed = 1;break;case PlaybackStateCompat.STATE_PAUSED:mPlaySpeed = 0;break;case PlaybackStateCompat.STATE_FAST_FORWARDING:mPlaySpeed = 3;break;case PlaybackStateCompat.STATE_REWINDING:mPlaySpeed = -3;break;}mPlaybackStateCompat = new PlaybackStateCompat.Builder(mPlaybackStateCompat).setState(mPlayStatus, mPlayTime, mPlaySpeed).build();
}

        这里的播放状态转换成对应的数值,最终保存到 mPlaybackStateCompat 中。

二、获取播放状态

        这里我们在来看一下 getPlaybackState() 获取播放状态的方法。

1、AvrcpPlayer        

getPlaybackState

private int mPlayStatus = PlaybackStateCompat.STATE_NONE;
private PlaybackStateCompat mPlaybackStateCompat;public PlaybackStateCompat getPlaybackState() {if (DBG) {Log.d(TAG, "getPlayBackState state " + mPlayStatus + " time " + mPlayTime);}return mPlaybackStateCompat;
}

        AvrcpPlayer 主要包含有关远程播放器的信息,所以对于车机端来说这里是获取手机播放器播放状态的方法。在 getPlaybackState() 中值返回一个 PlaybackStateCompat 变量,而 PlaybackStateCompat 正是上面回调接口最终保存的播放状态。

        所以对于播放状态还是要以 onPlayStatusChanged() 接口的回调信息为主,这才是协议栈实时反馈的最新状态。而 getPlaybackState() 只有在初始化的时候使用,这时由于 onPlayStatusChanged() 还未注册完成或者初始化时间段内播放状态没有变化,才通过 getPlaybackState() 方法主动获取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/833417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

链表经典面试题01

目录 引言 面试题01:返回倒数第k个节点 题目描述: 思路分析: 代码展示: 面试题02:链表的回文结构 题目描述: 描述 思路分析: 代码展示: 面试题03:相交链表 题目描述: 思路分析: 代码展示: 小结: 引言 这次的题均来自力扣和牛客有关链表的经典面试题,代码只会展示…

go语言自定义排序接口Interface实现示例 sort.Sort(data Interface) 快速排序 pdqsort

go语言sort.Sort(data Interface) 排序接口自定义排序实现,golang里面的sort包中的Sort方法底层使用的是 pdqsort的一个快速排序算法, 我们可以将要排序的对象实现Interface接口后直接丢个这个函数即可自动按照我们指定的方式进行数据快速排序。 sort函…

C++从入门到精通——类的6个默认成员函数之拷贝构造函数

拷贝构造函数 前言一、拷贝构造函数概念理解定义 二、拷贝构造函数的特征三、注意要点写法实践传址返回与引用返回的区别传址返回引用返回 传值返回和传址返回的对比总结测试 前言 类的6个默认成员函数:如果一个类中什么成员都没有,简称为空类。 空类中…

抢占用户|AI助力企业高效挖掘潜在客户,推动高质量转化

随着人工智能(AI)技术的崛起,企业终于可以在这个数字化时代获得一种强大的工具,帮助企业迅速而准确地找到潜在客户。AI不仅能够处理海量的数据,还能自动分析和识别潜在客户的特征和行为模式,为企业营销提供…

母婴用品网站设计与实现 java母婴用品网站源代码+论文+ppt

母婴用品网站设计与实现:基于JSP与MySQL的实践探索 引言 随着信息化时代的到来,母婴用品网站作为信息获取和商品交易的平台,其开发与设计成为了一个迫切的课题。本文将探讨如何利用JSP技术和MySQL数据库构建一个功能完备、用户友好的母婴用品网站。 系统概述 背景与必要…

【WEEK11】 【DAY1】Employee Management System Part 2【English Version】

2024.5.6 Monday Continuing from 【WEEK10】 【DAY2】Employee Management System Part 1【English Version】 Contents 10.3. Page Internationalization10.3.1. Preparation10.3.2. Configuration File Writing10.3.2.1. Create an i18n (abbreviation for internationaliza…

YOLOv8深度剖析专栏导航

本专栏计划更新关于YOLOv8目标检测、实例分割、关键点检测、旋转目标检测任务的实践和理论知识。实践篇会包括训练自己的数据集、并对模型进行验证、预测和导出;理论篇会介绍各任务的预测流程和训练流程。下面是已更新的文章目录: 1.软件安装及YOLOv8环境…

系统守护者:揭秘限流的四大算法与实战攻略

在网络世界的广阔天地中,服务如同繁忙的港口,每天迎来送往数不尽的请求。然而,潮水般的流量背后隐藏着风险,稍有不慎,系统便会因不堪重负而倾覆。这时,"限流"便如同智慧的灯塔,指引着…

专业的保密网文件导入导出系统,让文件流转行为更可控安全

军工单位因其涉及国防安全和军事机密,对保密工作有极高的要求,通常会采取严格的网络隔离措施来保护敏感信息和提高网络安全性。常见的方式是通过物理隔离将网络彻底分隔开来,比如保密网和非保密网。网络隔离后,仍有数据交换的需求…

Linux命令--tcpdump命令--使用与详解

原文网址:Linux命令--tcpdump命令--使用与详解_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Linux的tcpdump命令的用法。 tcpdump可以输出网络的通信记录,可以用来排查问题、查看被攻击网站的详细情况等。 示例 捕获eth0的数据包 tcpdump -i ens33 捕…

GORM的常见命令

文章目录 一、什么是GORM?二、GORM连接mysql以及AutoMigrate创建表三、查询1、检索此对象是否存在于数据库(First,Take,Last方法)2、Find()方法检索3、根据指定字段查询 四、更新1、Save() 保存多个字段2、更新单个字段 五、删除 一、什么是G…

Python中设计注册登录代码

import hashlib import json import os import sys # user interface 用户是界面 UI """ 用户登录系统 1.注册 2.登陆 0.退出 """ # 读取users.bin def load(path): return json.load(open(path, "rt")) # 保存user.bin def save(dic…

Figma 高效技巧:设计系统中的图标嵌套

Figma 高效技巧:设计系统中的图标嵌套 在设计中,图标起着不可或缺的作用。一套便捷易用的图标嵌套方法可以有效提高设计效率。 分享一下我在图标嵌套上走过的弯路和经验教训。我的图标嵌套可以分三个阶段: 第一阶段:建立图标库 一…

目标检测实战(八): 使用YOLOv7完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)

文章目录 一、目标检测介绍二、YOLOv7介绍三、源码/论文获取四、环境搭建4.1 环境检测 五、数据集准备六、 模型训练七、模型验证八、模型测试九、错误总结9.1 错误1-numpy jas mp attribute int9.2 错误2-测试代码未能跑出检测框9.3 错误3- Command git tag returned non-zero…

【unity】(2)GameObject

GameObject类是基本的游戏对象类型,它可以用来代表场景中的任何实体。 基本属性 name 类型:string说明:GameObject的名称。用法: GameObject go new GameObject(); go.name "My GameObject";activeSelf 类型&#xf…

Apple OpenELM设备端语言模型

Apple 发布的 OpenELM(一系列专为高效设备上处理而设计的开源语言模型)引发了相当大的争论。一方面,苹果在开源协作和设备端AI处理方面迈出了一步,强调隐私和效率。另一方面,与微软 Phi-3 Mini 等竞争对手相比&#xf…

森林消防新利器:高扬程水泵的革新与应用/恒峰智慧科技

随着全球气候变化的加剧,森林火灾的频发已成为威胁生态安全的重要问题。在森林消防工作中,高效、快速的水源供给设备显得尤为重要。近年来,高扬程水泵的广泛应用,为森林消防工作带来了新的希望与突破。 一、高扬程水泵的技术优势 …

【Node.js】使用 PostgreSQL、Sequelize 和 Express.js 进行 Node.js 认证

使用 PostgreSQL、Sequelize 和 Express.js 进行 Node.js 认证 作者:Racheal Kuranchie 来源:https://medium.com/rachealkuranchie/node-js-authentication-with-postgresql-sequelize-and-express-js-20ae773da4c9 使用 PostgreSQL、Sequelize 和 Expr…

Linux上安装及卸载OpenJDK

Linux上安装Java Development Kit (JDK) 8的步骤如下: 1. 添加Java JDK 8的Yum源 首先,你需要添加Java JDK 8的Yum源到系统。这可以通过下载并安装Oracle JDK的方式完成,但由于Oracle JDK在某些情况下可能需要遵守特定的许可协议&#xff0c…

探索Baidu Comate:编程世界中的新利器

文章目录 Baidu Comate 介绍Baidu Comate的优势Baidu Comate安装过程Baidu Comate实战演练代码调优代码解释代码生成注释生成 总结 Baidu Comate 介绍 随着GPT的大火,衍生了各种AI工具,这些AI工具遍布在各行业各领域中,有AI写作、AI办公、AI…