AAOS CarMediaService 服务框架

news2024/11/20 21:17:34

文章目录

      • 前言
      • 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 {
        @Override
        public 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.coloradmin.cn/o/1111820.html

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

相关文章

JVM第十五讲:调试排错 - Java 内存分析之堆外内存

调试排错 - Java 内存分析之堆外内存 本文是JVM第十五讲&#xff0c;Java 内存分析之堆外内存调试排错。Java 堆外内存分析相对来说是复杂的&#xff0c;美团技术团队的Spring Boot引起的“堆外内存泄漏”排查及经验总结可以为很多Native Code内存泄漏/占用提供方向性指引。 文…

政企互动 | 雨花台区委统战部一行走访调研聚铭网络

2023年10月19日上午&#xff0c;雨花台区委统战部副部长、台侨办主任勾宏展一行3人到聚铭网络调研走访&#xff0c;聚铭网络总经理唐开达热情接待了来访一行&#xff0c;并详尽地介绍了聚铭网络的发展历程、产品体系、企业文化等相关情况。 在聚铭网络总经理唐开达的陪同下&am…

Mysql表结构差异比较

1、背景 我们在开发过程中&#xff0c;大部分情况下都是好几个版本一起并行&#xff0c;有时候如果某个版本表结构改动较大&#xff0c;但是忘记了记录DDL脚本&#xff0c;这个时候需要人工去把新增或修改的DDL脚本整理出来&#xff08;主要是为了解决 数据库新增字段&#xff…

ArcGIS笔记9_数据源缺少空间参考信息?如何定义坐标系?

本文目录 前言Step 1 确定好要赋予给目标文件的恰当坐标系Step 2 定义坐标系 前言 有时从其他软件转换得到了shp文件&#xff0c;拖到ArcGIS后却出现“未知的空间参考&#xff1a;添加的数据源缺少空间参考信息 不能投影”的提示&#xff0c;如下图所示&#xff1a; 这种情况就…

go-fastdfs安装(国产分布式文件系统)

开源协议&#xff1a; Unlicense官网地址&#xff1a; https://sjqzhang.github.io/go-fastdfs/#vision安装: wget --no-check-certificate https://github.com/sjqzhang/go-fastdfs/releases/download/v1.3.1/fileserver -O fileserver && chmod x fileserver &…

【AIGC核心技术剖析】Hotshot-XL 一种 AI 文本转 GIF 模型(论文 + 代码:经过训练可与Stable Diffusion XL一起使用)

Hotshot-XL 是一种 AI 文本转 GIF 模型,经过训练可与Stable Diffusion XL一起使用。 Hotshot-XL 可以使用任何经过微调的 SDXL 模型生成 GIF。这意味着两件事: 您将能够使用您可能想要使用的任何现有或新微调的 SDXL 模型制作 GIF。 如果您想制作个性化主题的 GIF,您可以…

一张图帮你看懂,在浏览器输入网址回车后,都发生了什么?

首先我们来看图&#xff1a; 当我们在浏览器中输入一个网址&#xff0c;例如&#xff1a;baidu.com&#xff0c;按下回车键后&#xff0c;会发生什么呢&#xff1f; 主要会发生以下这些过程&#xff1a;域名解析&#xff08;获取IP地址&#xff09;、建立HTTP连接、发送HTTP请…

通用音乐播放器蜂鸣器AX301开发板verilog,视频/代码

名称&#xff1a;通用音乐播放器代码&#xff0c;蜂鸣器播放音乐 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码说明&#xff1a;本代码为音乐播放器通用代码&#xff0c;只需修改管脚即可适配其他开发板 代码功能&#xff1a; 设计一个音乐播放器&#xff0c;使用…

C#面对对象(英雄联盟人物管理系统)增加,查询,删除

目录 英雄信息类 因为要在两个窗体里面调用字典&#xff0c;所以要写一个字典的静态变量 添加功能 查询功能 删除功能 英雄信息类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Windo…

Required MultipartFile parameter ‘file‘ is not present

出现这个原因我们首先想到的是加一个RequestParam("file")&#xff0c;但是还有可能的原因是因为我们的名字有错误 <span class"input-group-addon must">模板上传 </span> <input id"uploadFileUpdate" name"importFileU…

Shell 脚本案例

1.编写hello world脚本 #!/bin/bash ############################################################## # File Name: hello_world.sh # Version: V1.0 # Author: oldchild # Email: 2363543991qq.com # Organization: https://blog.csdn.net/m0_63636799?spm1000.2115.3001.…

【自用重要】概率论中θ和θ尖的区别【计算时的一般方法】

θ就相当于x&#xff0c;是一个值。 θ尖就相当于X&#xff0c;是一个量。 在做分布函数的时候&#xff0c;最好把θ尖换成Z的形式&#xff0c;因为他们都是量&#xff0c;这样比较好看。 在做不等式的时候&#xff0c;一般把量放在中间进行计算&#xff0c;因为随机变量有分…

Kubernetes技术与架构-服务

从软件系统架构设计分层的角度看&#xff0c;Kubernetes的Service是基于Pod的上层&#xff0c;业务应用部署在Pod中&#xff0c;使用Service绑定Pod部署的应用&#xff0c;Service可以对外或者对上层提供服务&#xff0c;当Pod集群在系统调度的过程中发生弹性伸缩的时候&#x…

Linux实用指令-指定运行级别、帮助指令

一、 指定运行级别 1.运行级别说明&#xff1a; 0:关机 1:单用户[找回丢失密码] 2:多用户状态没有网络服务 3:多用户状态有网络服务 4:系统未使用保留给用户 5:图形界面 6:系统重启 常用运行级别是3和5&#xff0c;要修改默认的运行级别。可改文件/etc/inittab 的id:5:initd…

如何识别人工智能生成的图像

随着人工智能成像变得更加先进&#xff0c;从拍摄的场景中辨别真实情况变得越来越困难。这在很多方面都会成为一个问题——从假新闻到真实人物的深度伪造。 我们唯一的机会就是更加敏锐地识别假货。 我最近进行了在线人工智能识别&#xff0c;能够从人造版本中正确选择所有真…

十七、文件(2)

本章概要 文件系统路径监听文件查找文件读写 文件系统 为了完整起见&#xff0c;我们需要一种方法查找文件系统相关的其他信息。在这里&#xff0c;我们使用静态的 FileSystems 工具类获取"默认"的文件系统&#xff0c;但你同样也可以在 Path 对象上调用 getFileS…

【Java 进阶篇】HTML DOM 事件详解

当用户在网页上点击按钮、输入文本、鼠标移动到某个区域或执行其他互动操作时&#xff0c;这些动作都可以触发事件。HTML DOM&#xff08;文档对象模型&#xff09;允许我们使用JavaScript来捕获、处理和响应这些事件&#xff0c;以实现网页的交互和动态性。本篇博客将围绕HTML…

选择最适合的产品研发和运营管理工具

Zoho Projects项目管理工具&#xff0c;以其卓越的敏捷开发协作能力&#xff0c;有效提升了产品规划和研发效率。 以下是对其优势的深入探讨&#xff1a; 一、面临的问题分析 需求变动频繁&#xff1a;在快速变化的市场环境中&#xff0c;如何灵活应对需求变动是一大挑战。跨…

数据库中了mkp勒索病毒怎么办?Mkp勒索病毒解密,数据恢复

相信在本月有很多的企业都遭到了mkp勒索病毒的攻击&#xff0c;该勒索病毒非常狡猾&#xff0c;利用中秋国庆假期期间&#xff0c;对很多的企业服务器进行了攻击&#xff0c;导致服务器内的所有文件都被加密&#xff0c;严重影响了企业的正常工作&#xff0c;经过最近一段时间对…

微信小程序怎么注册_微信小程序怎么可以免费认证

随着微信小程序的日益普及&#xff0c;越来越多的企业和个人开始关注如何注册微信小程序。本文将详细介绍微信小程序注册的步骤以及注意事项&#xff0c;帮助大家更好地了解如何成功注册微信小程序。 一、了解微信小程序注册的意义 微信小程序是一种轻量级的应用程序&#xff…