AAOS CarMediaService 服务框架
文章目录
- 前言
- MediaSession
- CarMediaService
- 作用是什么?提供了哪些接口?如何使用?
- CarMediaService的实现
- 总结
前言
CarMediaService 是AAOS中统一管理媒体播放控制、信息显示和用户交互等功能的服务。这一服务依赖于android MediaSession框架。 所以首先需要简单的了解一下MediaSession。
MediaSession
MediaSession 框架规范了音视频应用中界面与播放器之间的通信接口,实现界面与播放器之间的完全解耦。MediaSession 框架定义了媒体会话和媒体控制器两个重要的类,它们为构建多媒体播放器应用提供了一个完善的技术架构。

AAOS上面的MediaSession的控制框图如上主要是MediaControl和MediaSession两个类直接的交互。
-
MediaControl是UI端控制Service端的类,在AAOS中所有的app播放控制客户端的实现都是carMediaApp中MediaControl的实现的(包括蓝牙audio localplayer界面中暂停播放,下一首 上一首等等)。
-
MediaSession是服务端, 这个服务端包括(蓝牙的src\com\android\bluetooth,和/apps/Car/LocalMediaPlayer)。这这里面实现了Mediassion 的callback 用来响应client 端UI的控制。 而响应之后的状态改变可以通过继承MediaControl的callback 在客户端实现。
CarMediaService
作用是什么?提供了哪些接口?如何使用?
-
用途
CarMediaService通过CarMediaManager给外部应用提供使用的API。
这些api允许开发者控制车辆中的主要媒体源,以及获取与这一媒体源相关的更新信息。通过这个 API 来实现媒体播放控制、信息显示和用户交互等功能。 -
接口
CarMediaManger是客户端 通过AIDL的接口 调用到CarMediaService中。 提供的AIDIL的接口如下:
- 获取/设置提供模式下当前活动的媒体源。
其中模式包括播放和浏览: 是指应用的操作可以是浏览媒体 或者是操作播放媒体。
其中MediaSource的理解:可以认为是执行具体播放操作的一个应用 是媒体播放控制的对象比如蓝牙音乐播放器、本地的播放器等等。 - 注册/反注册回调,监听媒体活动源的更新。同样模式可以是浏览或者播放。
综上可以看到carMediaService 是实现所有媒体相关的ui 浏览和控制的统一管理。 监听媒体源的变化,控制活动和非活动媒体源的播放、退出、暂停等等。
interface ICarMedia {/** Gets the currently active media source for the provided mode */ComponentName getMediaSource(int mode);/** Sets the currently active media source for the provided mode */void setMediaSource(in ComponentName mediaSource, int mode);/** Register a callback that receives updates to the active media source */void registerMediaSourceListener(in ICarMediaSourceListener callback, int mode);/** Unregister a callback that receives updates to the active media source */void unregisterMediaSourceListener(in ICarMediaSourceListener callback, int mode);/** Retrieve a list of media sources, ordered by most recently used */List<ComponentName> getLastMediaSources(int mode);/** Returns whether the browse and playback sources can be changed independently. */boolean isIndependentPlaybackConfig();/** Sets whether the browse and playback sources can be changed independently. */void setIndependentPlaybackConfig(boolean independent);
}
- 使用流程
首先获取CarMediaManager,然后注册MediaSource变化的监听,在mediasource有变化的时候更新ui。
mHandler = new Handler(application.getMainLooper());mMediaSourceListener = componentName -> mHandler.post(() -> updateModelState(mInputFactory.getMediaSource(componentName)));try {mCarMediaManager = mInputFactory.getCarMediaManager(mCar);mCarMediaManager.addMediaSourceListener(mMediaSourceListener, mode);MediaSource src = mInputFactory.getMediaSource(mCarMediaManager.getMediaSource(mode));if (Log.isLoggable(TAG, Log.INFO)) {Log.i(TAG, "Initializing with " + src);}updateModelState(src);} catch (CarNotConnectedException e) {Log.e(TAG, "Car not connected", e);}
CarMediaService的实现

- carMediaService中初始化流程
- 获取mPrimaryMediaComponents
获取的方式是通过遍历系统的所有package、然后查看有MediaBroswerService的package。
在AAOS 默认Bluetooth有MediaBroswerService,所以默认的package是com.android.bluetooth。
private ComponentName getMediaService(@NonNull ComponentName componentName) {String packageName = componentName.getPackageName();String className = componentName.getClassName();PackageManager packageManager = mContext.getPackageManager();Intent mediaIntent = new Intent();mediaIntent.setPackage(packageName);mediaIntent.setAction(MediaBrowserService.SERVICE_INTERFACE);List<ResolveInfo> mediaServices = packageManager.queryIntentServicesAsUser(mediaIntent,PackageManager.GET_RESOLVED_FILTER, ActivityManager.getCurrentUser());for (ResolveInfo service : mediaServices) {String serviceName = service.serviceInfo.name;if (!TextUtils.isEmpty(serviceName)// If className is not specified, returns the first service in the package;// otherwise returns the matched service.// TODO(b/136274456): find a proper way to handle the case where there are// multiple services and the className is not specified.&& (TextUtils.isEmpty(className) || serviceName.equals(className))) {return new ComponentName(packageName, serviceName);}}}
-
注册MediaSessionActive的回调
当服务端的MediaSession 设置为active的时候,回调到这个SessionChangedListener中 -
启动MediaConnectService
MediaConnectorService会调用MediaConnectorService的onStartCommand。
onStartCommand中会获取当前应用的MediaControl设置到PlaybackViewModel。
PlaybackViewModel利用这个control对MediaSession的service端进行控制。
控制是在service端实现mediaControl的onPrepare、onPlay等实现的。
如果MediaSession当前是播放的状态那么会stop掉。如果不是的话 会先进行prepare操作。
private void initUser(@UserIdInt int userId) {mPrimaryMediaComponents[MEDIA_SOURCE_MODE_PLAYBACK] = isCurrentUserEphemeral()? getDefaultMediaSource() : getLastMediaSource(MEDIA_SOURCE_MODE_PLAYBACK);mPrimaryMediaComponents[MEDIA_SOURCE_MODE_BROWSE] = isCurrentUserEphemeral()? getDefaultMediaSource() : getLastMediaSource(MEDIA_SOURCE_MODE_BROWSE);mActiveUserMediaController = null;updateMediaSessionCallbackForCurrentUser();notifyListeners(MEDIA_SOURCE_MODE_PLAYBACK);notifyListeners(MEDIA_SOURCE_MODE_BROWSE);startMediaConnectorService(shouldStartPlayback(mPlayOnBootConfig), currentUser);}}
- SessionChanged 的回调

SessionChanged回调到onActiveSessionsChanged。回调的参数是所有active的mediaControl。这里面会遍历所有control,如果control的状态是playing 并且其MediaSource跟当前存储的PrimaryMediaSource不一样的话 会更新control的MediaSource到PrimaryMediaSource。
private class SessionChangedListener implements OnActiveSessionsChangedListener {@Overridepublic void onActiveSessionsChanged(List<MediaController> controllers) {if (ActivityManager.getCurrentUser() != mCurrentUser) {Slog.e(CarLog.TAG_MEDIA, "Active session callback for old user: " + mCurrentUser);return;}mMediaSessionUpdater.registerCallbacks(controllers);}}
-
MediaController的回调

这个会回调到onPlaybackStateChanged,回调的状态是playing而且跟回调之前的状态不一样的时候 也会调用setPrimaryMediaSource进行primary mediasource的更新。
public void onPlaybackStateChanged(@Nullable PlaybackState state) {if (state.getState() == PlaybackState.STATE_PLAYING&& state.getState() != mPreviousPlaybackState) {ComponentName mediaSource = getMediaSource(mMediaController.getPackageName(),getClassName(mMediaController));if (mediaSource != null) {setPrimaryMediaSource(mediaSource, MEDIA_SOURCE_MODE_PLAYBACK);}}mPreviousPlaybackState = state.getState();}}
总结
CarMediaService 的实现是通过注册MediaSessionActive 和 MediaController的callback 来监听当前用户所有应用 有关媒体播放浏览等事件。当事件发生时
更新AAOS界面的信息和控制的控件。
相关文章:
AAOS CarMediaService 服务框架
文章目录 前言MediaSessionCarMediaService作用是什么?提供了哪些接口?如何使用?CarMediaService的实现总结 前言 CarMediaService 是AAOS中统一管理媒体播放控制、信息显示和用户交互等功能的服务。这一服务依赖于android MediaSession框架…...
gRPC之gRPC转换HTTP
1、gRPC转换HTTP 我们通常把RPC用作内部通信,而使用Restful Api进行外部通信。为了避免写两套应用,我们使用grpc- gateway 把gRPC转成HTTP。服务接收到HTTP请求后,grpc-gateway把它转成gRPC进行处理,然后以JSON 形式返回数据。…...
【十四】记一次MySQL宕机恢复过程,MySQL INNODB 损坏恢复
记一次MySQL宕机恢复过程 简介:一个业务数据库疏于运维管理,突然在今天崩溃宕机了,真是让人抓狂,上面也不知道积累了多久的数据,平时也没有定期做好备份,这下岂不是瞎了啊,经过不断的收集信息和…...
从0开始在Vscode中搭建Vue2/3项目详细步骤
1.安装node.js:Node.js下载安装及环境配置教程【超详细】_nodejs下载_WHF__的博客-CSDN博客 node.js自带npm,无需单独安装。 验证: node -v npm -v 2.先简单创建一个空文件夹,vscode进入该文件夹,并打开终端。 3.安装cnpm&…...
JavaScript ES6类的定义与继承
文章目录 一、class方式定义类1.认识class定义类2.类和构造函数的异同3.类的构造函数4.类的实例方法5.类的访问器方法6.类的静态方法 二、继承1.extends实现继承2.super关键字3.继承内置类4.类的混入mixin 三、ES6转ES51.class转换2.extends转换 四、多态 一、class方式定义类 …...
中科芯与IAR共建生态合作,IAR集成开发环境全面支持CKS32系列MCU
中国上海–2023年10月18日–嵌入式开发软件和服务的全球领导者IAR今日宣布,与中科芯集成电路有限公司(以下简称中科芯)达成生态合作,IAR已全面支持CKS32系列MCU的应用开发。这一合作将进一步推动嵌入式系统的发展,并为…...
设计模式:外观模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)
大家好!本节主要介绍设计模式中的外观模式。 简介: 外观模式,它是一种设计模式,它为子系统中的一组接口提供一个统一的、简单的接口。这种模式主张按照描述和判断资料来评价课程,关键活动是在课程实施的全过程中进行…...
Leetcode—34.在排序数组中查找元素的第一个和最后一个位置【中等】
2023每日刷题(六) Leetcode—34.在排序数组中查找元素的第一个和最后一个位置 实现代码 /*** Note: The returned array must be malloced, assume caller calls free().*/ int lower_bound(int *arr, int numsSize, int target) {// 左闭右开区间[lef…...
Java 8 新特性 Ⅱ
方法引用 举例: Integer :: compare 理解: 可以看作是基于lambda表达式的进一步简化 当需要提供一个函数式接口的实例时, 可以使用lambda表达式提供实例 当满足一定条件下, 可以使用方法引用or构造器引用替换lambda表达式 实质: 方法引用作为函数式接口的实例 (注: 需要熟悉…...
C语言学习书籍推荐
C语言学习书籍推荐如下: 《C程序设计语言》(The C Programming language):这本书由C语言创始人Brian W. Kernighan和Dennis M. Ritchie所写,是介绍标准C语言及其程序设计方法的权威性经典著作。《C陷阱与缺陷》&#…...
IntelliJ IDEA Maven加载超时问题
IDEA创建Maven项目遇到如下错误: Could not transfer artifact org.apache.maven.plugins:maven-compiler-plugin:pom:3.10.1 from/to central (Central Repository:): Connect to repo.maven.apache.org:443 [repo.maven.apache.org/146.75.112.215] failed: conn…...
Spring中事务失效的几种场景及解决办法
未抛出异常:如果在一个带有事务的方法中没有抛出异常,Spring无法检测到事务失败,从而无法回滚。解决方法是确保在事务中遇到错误时抛出异常。 异常被捕获:如果在一个带有事务的方法中抛出异常,但被捕获并处理了&#…...
第五届太原理工大学程序设计竞赛新生赛(初赛)题解
第五届太原理工大学程序设计竞赛新生赛(初赛)题解 时隔半年重做一次,还是有几道不会,,,,, ⭐️A.饿饿饭饭 题目: 🌟题解: 很简单,签…...
微信小程序开发之后台数据交互及wxs应用
目录 一、后端准备 1. 应用配置 2. 数据源配置 二、数据库 1. 创建 2. 数据表 3. 数据测试 三、前端 1. 请求方法整合 2. 数据请求 3. WXS的使用 4. 样式美化 5. 页面 一、后端准备 通过SpringMVC及mybatis的技术学习,还有前后端分离的技术应用&…...
Java进阶篇--并发容器之ThreadLocal内存泄漏
目录 ThreadLocal内存泄漏的原因? 改进和优化 cleanSomeSlots方法 expungeStaleEntry方法 replaceStaleEntry方法 为什么使用弱引用? Thread.exit() ThreadLocal内存泄漏最佳解决方案 在使用完毕后立即清理ThreadLocal 使用InheritableThreadL…...
js实现红包雨功能(canvas,react,ts),包括图片不规则旋转、大小、转速、掉落速度控制、屏幕最大红包数量控制等功能
介绍 本文功能由canvas实现红包雨功能(index.tsx)本文为react的ts版。如有其他版本需求可评论区观赏地址,需过墙 import React, { Component } from react; // import ./index.css; import moneyx from /assets/images/RedEnvelopeRain/bal…...
【数字IC设计/FPGA】FIFO与流控机制
流控,简单来说就是控制数据流停止发送。常见的流控机制分为带内流控和带外流控。 FIFO的流水反压机制 一般来说,每一个fifo都有一个将满阈值afull_value(almost full)。当fifo内的数据量达到或超过afull_value时,将满…...
C++笔记之遍历vector的所有方式
C笔记之遍历vector的所有方式 —— 2023年4月15日 上海 code review 文章目录 C笔记之遍历vector的所有方式1.普通for循环2.迭代器版3.const迭代器4.C11引入的范围for循环5.使用auto关键字和迭代器6.使用std::for_each算法7.使用std::for_each和lambda表达式8.普通版vector::at…...
OpenCV 笔记(2):图像的属性以及像素相关的操作
Part11. 图像的属性 11.1 Mat 的主要属性 在前文中,我们大致了解了 Mat 的基本结构以及它的创建与赋值。接下来我们通过一个例子,来看看 Mat 所包含的常用属性。 先创建一个 3*4 的四通道的矩阵,并打印出其相关的属性,稍后会详细…...
基于指数分布优化的BP神经网络(分类应用) - 附代码
基于指数分布优化的BP神经网络(分类应用) - 附代码 文章目录 基于指数分布优化的BP神经网络(分类应用) - 附代码1.鸢尾花iris数据介绍2.数据集整理3.指数分布优化BP神经网络3.1 BP神经网络参数设置3.2 指数分布算法应用 4.测试结果…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
