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的接口如下:

  1. 获取/设置提供模式下当前活动的媒体源。
    其中模式包括播放和浏览: 是指应用的操作可以是浏览媒体 或者是操作播放媒体。
    其中MediaSource的理解:可以认为是执行具体播放操作的一个应用 是媒体播放控制的对象比如蓝牙音乐播放器、本地的播放器等等。
  2. 注册/反注册回调,监听媒体活动源的更新。同样模式可以是浏览或者播放。

综上可以看到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中初始化流程
  1. 获取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);}}}
  1. 注册MediaSessionActive的回调
    当服务端的MediaSession 设置为active的时候,回调到这个SessionChangedListener中

  2. 启动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界面的信息和控制的控件。

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

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

相关文章

搭建NGINX服务 如何统计网页访问量

一、搭建Nginx服务 搭建之前需要查看一下我们的内核数制 我们进行简单的内核优化 命令&#xff1a;ulimit -n 65535 安装Nginx服务 第一步 关闭防火墙和安全机制 systemctl stop firewalld #关闭防火墙 systemct disable firewalld #开机自动关闭防火墙 setenfor…

美创科技信创数据安全「利基者」!

近日&#xff0c;第一新声研究部正式发布《2023年中国信创网络安全产品竞争力象限》&#xff08;下称“象限报告“&#xff09;。 ◼︎ 象限报告综合考虑企业占有率、在技术/应用上的成熟度、在客户方面的交付完成度及口碑、产品在市场/营销/商业模式/行业拓展等战略上的领先性…

无人机新手防炸飞行技巧

不要在室内飞行,容易撞墙。起飞前设置好避障和返航模式。使用模拟器熟练掌握操控。选择开阔环境目视起飞。使用低速档平稳飞行。合理使用避障功能,不要盲目依赖。使用九宫格避障法。留意电量,及时返航。极低电量时放弃强行返航。飞行后及时为电池充电保养。

文件管理系统的基本认识

1.文件的属性 文件的定义:一组有意义的信息的集合。 1.文件名: 由创建文件的用户决定文件名&#xff0c;主要是为了方便用户找到文件&#xff0c;同一目录下不允许有重名文件。 2.标识符: 一个系统内的各文件标识符唯一&#xff0c;对用户来说毫无可读性&#xff0c; 因此…

NetCore/Net8下使用Redis的分布式锁实现秒杀功能

目的 本文主要是使用NetCore/Net8加上Redis来实现一个简单的秒杀功能&#xff0c;学习Redis的分布式锁功能。 准备工作 1.Visual Studio 2022开发工具 2.Redis集群&#xff08;6个Redis实例&#xff0c;3主3从&#xff09;或者单个Redis实例也可以。 实现思路 1.秒杀开始…

mysql按照日期分组统计数据(date_formatstr_to_date)

学习链接 mysql按照日期分组统计数据 博主-山茶花开时的 【Mysql专栏学习】 mysql按照日期分组统计数据 Mysql的date_format函数想必大家都使用过吧&#xff0c;一般用于日期时间转化&#xff0c;如下所示 # 可以得出 2023-01-01 08:30:50 select DATE_FORMAT(2023-01-01…

【合宙Air700E/780E短信转发】短信转发移动联通 不要钉钉不要微信,转发自建服务器-傻瓜式搭建

官方提供的教程介绍了通过钉钉、微信等工具接收短信验证码的方法&#xff0c;但最终实现的目的是获取验证码&#xff0c;而不是通过工具间接获得。 因此&#xff0c;我们可以直接调用API接口来获取验证码&#xff0c;从而达到更快、更便捷地获得验证码的目的。 所以做了一个服…

STM32内部flash闪存的总结

最近在做无人船和机巢远程在线升级的项目&#xff0c;牵扯到flash的操作&#xff0c;特此记录&#xff0c;便于以后查找。IMU也用到过&#xff0c;当时没记录 具体细节看 E:\Documets\AY\a-project\IMU\IMU16500\S0IMU v3.3 study\User\Driver\source eeprom.c E:\Documets\A…

【Java基础面试三十四】、接口中可以有构造函数吗?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;接口中可以有构造函数吗…

mysql检验分区性能的操作

mysql检验分区性能的操作 创建两个结构相同但是一个有分区另外一个没有分区的表 如上图我们给part_tab5创建的分区为1024个&#xff0c;因为mysql中允许最多有1024个分区&#xff1b;之前我测试的是创建8个分区&#xff0c;然后插入500万条数据&#xff0c;然后按照id查询&…

【持续更新】tutorial-Linux-Markdown-etc(Linux、命令、Markdown、md、Tex、LaTex)

1. Linux命令 1.1 常用 查看文件夹下文件数量: ls -l | wc -l7zip: 解压&#xff1a;7z x compressed_file.7z -o/path/to/destination # 注意-o和目标路径是连起来的&#xff0c;没有空格压缩&#xff1a;7z a compressed_file.zip destination_path conda 查看 conda 拥有的…

浏览器调试模式获取链接信息(获取京东cookie为例)

通过浏览器的调试模式&#xff0c;获取京东cookie变量pt_pin和pt_key。 一、登录 1&#xff09;打开网页 浏览器打开手机版京东网页&#xff1a;m.jd.com 2&#xff09;登录账号 点击【登录】按钮&#xff0c;输入账号密码登录 二、调试模式 1&#xff09;停留在要调试的…

C/C++ 快速入门

参考&#xff1a;https://blog.csdn.net/gao_zhennan/article/details/128769439 1 下载Visual Studio Code并安装中文插件&#xff0c;此处不再叙述 2 插件安装C/C插件 3 使用快捷键【Ctr ~】打打开终端 验证并未安装编译器 4 我们即将使用【MinGW-64】做为编译器 https:…

[nlp] chathome—家居装修垂类大语言模型的开发和评估

ChatHome: Development and Evaluation of a Domain-Specific LanguageModel for Home Renovation ChatHome: 家居装修垂类大语言模型的开发和评估 1、摘要: 我们的方法包括两个步骤:首先,使用广泛的家庭装修数据集(包括专业文章、标准文档和网络内容)对通用模型进行后预训…

C/C++面试常见问题——指针和引用的区别

首先想要理解指针和引用的区别&#xff0c;我们要明确什么是指针&#xff0c;什么是引用 一&#xff0c;指针和引用的基本概念及特性 指针是一个特殊变量&#xff0c;其中存储着所指向变量的地址 指针主要有以下特性&#xff1a; 1. 在使用时需要*解引用 2. sizeof(指针)的…

ChatGPT/GPT4科研技术应用与AI绘图及论文高效写作

2023年我们进入了AI2.0时代。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车&#xff0c;就有可能被淘汰在这个数字化时代&#xff0c;如何能高效地处理文本、文献查阅、PPT…

大数据中间件——Kafka

Kafka安装配置 首先我们把kafka的安装包上传到虚拟机中&#xff1a; 解压到对应的目录并修改对应的文件名&#xff1a; 首先我们来到kafka的config目录&#xff0c;我们第一个要修改的文件就是server.properties文件&#xff0c;修改内容如下&#xff1a; # Licensed to the …

从Github中下载部分文件

我们经常回去Github中下载代码&#xff0c;但仓库中存在很多project代码。但我们如果只需要某一个或几个项目的代码&#xff0c;此时应该如何操作呢&#xff1f; 这里介绍两款工具&#xff0c;可以从仓库中下载部分文件的小工具: DownGit 和 GitZip 1. DownGit downGit 国内镜…

基于单片机设计的家用自来水水质监测装置

一、前言 本文介绍基于单片机设计的家用自来水水质监测装置。利用STM32F103ZET6作为主控芯片&#xff0c;结合水质传感器和ADC模块&#xff0c;实现对自来水水质的检测和监测功能。通过0.96寸OLED显示屏&#xff0c;将采集到的水质数据以直观的方式展示给用户。 随着人们对健…

DVWA-JavaScript Attacks

JavaScript Attacks JavaScript Attack即JS攻击&#xff0c;攻击者可以利用JavaScript实施攻击。 Low 等级 核心源码&#xff0c;用的是dom语法这是在前端使用的和后端无关&#xff0c;然后获取属性为phrase的值然后来个rot13和MD5双重加密在复制给token属性。 <script&…