【Android项目】本地FM收音机开发及源码简析

目录

1.概述

2.收音机的基本原理

3.收音机其他信息 RDS功能

4.Android开发FM收音机源码解析

5.App层如何设计本地FM应用

6. 总结

1.概述


本地FM(收音机)应用不同于现在的网络FM(喜马拉雅,考拉等),是由Android手机硬件的调谐芯片,通过接收和解调电台发出的电磁波的调频(FM)或调幅(AM)信号,从而播放和展示相应的节目信息。所以本地收音机应用一般不需要联网,其核心依赖于硬件调谐芯片。所以不是所有的手机都能收听本地收音机,但大部分的手机都支持。

2.收音机的基本原理


收音机的核心原理就是:电台播音员播出音频经过设备处理成电信号并搭载无线电波进行调制频率或者调制振幅后发射出来,收音机听过天线获取到电波信号,经过解调还原出电信号并且通过信号放大等操作输出到喇叭将电信号还原为为音频信号。

上面说到两种调制方式: AM(调幅)/ FM(调频);

那么为什么需要进行调制?

因为正常情况下人能够听到的声音频率是20--20Khz之间。声波在控制的传输介质为空气,但是衰减很大,传输距离很短,几十米左右。所以直接用声波进行传输是不现实的。但是无线电波在空中传输的介质是电磁场,并且传输距离长。所以将声波转化为电信号之后和无线电波进行调制,则拥有了长距离传输的特性。

AM(调幅)方式:信号波的信号调制在载波上,改变了载波的振幅。频率在503---1060KHz之间

FM(调频)方式:信号波的信号调制在载波上,改变了载波的频率。调频范围为76-108MHz,在我国为87.5-108MHz、日本为76-90MHz。

收音机这边接收信号并进行解调放大通过喇叭还原音频。

3.收音机其他信息 RDS功能


RDS全称“Radio Data System” 无线数据广播系统;上面我们只讲了信号波的传送,如果只有信号波,电台显示的信息会非常单调。只能展示当前的频率。但是电台除了这些还有电台的名称,节目信息,介绍等相关信息。这时,就需要就靠RDS的来完成了,它是在调频广播发射信号中利用副载波把电台名称等信息发送以数字的形式发送出去。收音机这边通过具有RDS功能的调谐芯片将信息进行解析出来,并且展示。

所以,使用RDS的前提是:电台和收音机调谐芯片都必须同时支持RDS的功能;但目前只有少部分的电台支持RDS。

RDS有两个核心的功能:AF和TA;

AF是指当当前台的信号低于某个值得时候自动搜索该台的其他信号好的频道并且进行自动切换。以达到更好的用户体验。

TA功能是一个强制性播放的功能,如果发生重大事故,紧急通告等交通信息,会强制性切换到该频率进行播放。

具体RDS功能可以搜索【FM收音机_RDS功能概述及编码】深入了解。

4.Android开发FM收音机源码解析


首先我们来看一下层级结构

硬件driver(由芯片厂家提供) -> HAL(遵循HAL接口协议) -> C动态库(JNI调用)-> Framework(RadioManager) -> Application(逻辑与界面)。

RadioManager这个类在系统API中是hide的,如果想在AndroidStudio中编译是需要做处理的,可自行查阅,但获取framework.jar应该都是必须的。

下面我用一张时序图来展示,咱们先不讨论在Application层面如果设计框架,先看一下如果我们在App中调用了tune(...)方法去播放某一个电台,从framework及其以下经过了那一些的流程。

以上时序图是基于8.0的源码绘制的,其实9.0的源码和8.0收音机的差别还挺多的。demo的结构变得多,源码中App的收音机demo是在目录:

android-8.0.0_r1\packages\apps\Car\Radio\src\com\android\car\radio\

上面的时序图似乎少了点什么?

HAL好像直接就和Framework交互了,中间不应该还有jni吗;所以我们找到目录

android-8.0.0_r1\frameworks\base\core\jni\android_hardware_Radio.cpp

我们知道jni起到的衔接java和c的作用,其实就是java中的方法和c中的方法进行一一相互映射,或者在jni中对应java的方法,并且对c的方法处理逻辑。

那么我们来看一下这几个类的方法

RadioTMoudle.java中的方法:

再看下android_hardware_Radio.cpp中对应

我们看到了什么?

RadioTMoudle.java中方法都在android_hardware_Radio.cpp中,只不过方法名都加上了固定的前缀,这只是jni的特色。说明这两个文件能够对应的上。

我们接着看,比如说

(void *)android_hardware_Radio_tune方法看看执行了什么

再看看ITuner.hal文件中的tune方法

似乎,接轨了。

5.App层如何设计本地FM应用


上面,我们简单的说完了Tuner底层的调用流程。那么问题来了,我一个做FM本地应用开发的,这些Framework都做好了。跟我有啥关系?其实不然,了解这些原理,能够在我们调试的时候更方便界定问题,难道底层就不会出错吗,对吧。而且,在定制的系统上,如果收音机定制的话,底层是会根据需求进行修改的,所以也是不稳定的。

那么如果设计应用层的框架结构呢。

答案:根据需求来。。。

假设我的需求是这样的,好吧,不是假设,实际上我的项目需求就是这样的。

别说话,看图。

简述下需求:

1- 主界面(Launcher)下方有个控制面板,可以对收音机进行操作。

2- 点击控制面板空白区域可以打开收音机的页面。收音机界面可以操作和显示,并收藏。 状态和外面控制面板保持一致

3- 外部可扩展的控制,盘控控制,语音控制等;

4- 遵循音频焦点策略

分析:

1- 控制面板的显示:采用widget桌面小部件的方式显示。和应用FM交互通过广播。

2- 点击空白区域打开,启动Activity界面。界面上进行操作,但是需要考虑,如果直接通过控制面板操作,则是不需要启动Activity也能播放。所以必须要有一个CoreService核 心服务在后台运行,不需要依赖界面。

3- 外部控制也应该是和Servicre进行交互。需要考虑其扩展性

4- 监听焦点获取与丢失并且进行逻辑处理。

设计:

经过上的分析,我们整理以下几个核心的点

CoreService 一个真正操作的核心服务

Activity 主界面

Widget 控制面板

代码设计模式:这个可以看自己,这里使用MVP模式。那么就会有两个Presenter:

RaidoPresenter 收音机核心操作(包含音频处理)

FavoritePresenter 收藏操作

其他外部控制,只需要设计数据交互模式即可。

最终:

来一草图

算了,我自己都看不清楚,用我的灵魂之手从新画个。

是不是清晰多了。这图就很明了了,应该很清晰。别说话,看图。

6. 总结


本篇文章比较简单了介绍了,Android本地收音机的开发的一些知识,关于这方面的资料。在网上还是比较少,通过自己的项目经验,在此输出此文,个人能力有限,难免可能有错误.

【Android项目】本地FM收音机开发及源码简析相关推荐

  1. android媒体焦点音量压低/暂停逻辑源码简析

    客户端通过AudioManager的调用requestAudioFocus请求焦点的过程中,其他媒体客户端会因媒体焦点丢失进行媒体压低或暂停,下面从framework层简单分析其过程. 首先调用Aud ...

  2. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

  3. django源码简析——后台程序入口

    django源码简析--后台程序入口 这一年一直在用云笔记,平时记录一些tips或者问题很方便,所以也就不再用博客进行记录,还是想把最近学习到的一些东西和大家作以分享,也能够对自己做一个总结.工作中主 ...

  4. ffmpeg实战教程(十三)iJKPlayer源码简析

    要使用封装优化ijk就必须先了解ffmpeg,然后看ijk对ffmpeg的C层封装! 这是我看ijk源码时候的笔记,比较散乱.不喜勿喷~ ijk源码简析: 1.ijkplayer_jni.c 封装的播 ...

  5. Spring Boot源码简析 @EnableTransactionManagement

    相关阅读 Spring Boot源码简析 事务管理 Spring Boot源码简析 @EnableAspectJAutoProxy Spring Boot源码简析 @EnableAsync Sprin ...

  6. Log-Pilot 源码简析

    Log-Pilot 源码简析 简单介绍 源码简析 Pilot结构体 Piloter接口 main函数 Pilot.Run Pilot.New Pilot.watch Pilot.processEven ...

  7. (Ajax)axios源码简析(三)——请求与取消请求

    传送门: axios源码简析(一)--axios入口文件 axios源码简析(二)--Axios类与拦截器 axios源码简析(三)--请求与取消请求 请求过程 在Axios.prototype.re ...

  8. java ArrayList 概述 与源码简析

    ArrayList 概述 与源码简析 1 ArrayList 创建 ArrayList<String> list = new ArrayList<>(); //构造一个初始容量 ...

  9. Android污点分析工具flowdroid源码简析

    flowdroid是一款对Android app进行风险分析的应用,下面深入其源码对其工作的流程进行相关的探究. 1.准备 a)下载相关源码(包括soot.heros.jasmin.soot-info ...

最新文章

  1. Map的分类和不同的应用场景
  2. shell脚本编程学习笔记(四)shell操作数据库
  3. jupyter notebook 插入图片
  4. 华为mate40pro更新鸿蒙时间,确认入网!鸿蒙系统将首发mate40Pro4G版,华为旧旗舰也迎来升级...
  5. c#关于JWT跨域身份验证解决方案
  6. java生成Json文件
  7. Error:Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apk
  8. tms570 can 接收大量数据_CAN通讯系列--AUTOSAR架构的CAN Interface7
  9. Spring学习记录-Java 11运行eureka-server报javax.xml.bind.JAXBContext not present错
  10. SpringCloud学习笔记016---在windows下搭建的Redis服务_在SpringBoot中使用Redis
  11. VBS 与 VBA 的区别
  12. (7)雅思屠鸭第七天:阅读中538个考点词一网打尽
  13. 竞拍网站服务器配置,GOM引擎新区竞拍脚本,GOM传奇服务端设置竞拍的方法和教程...
  14. 面对互联网寒冬裁员潮,HR都在干什么?
  15. Win10 网络连接处空白什么都没有,电脑无法上网
  16. 电脑共享文件打不开要如何解决
  17. 计算机 蓝牙鼠标卡顿,蓝牙鼠标卡顿、漂移现象的解决方法
  18. 油价小程序开发 - 手把手教你写小程序(适合初学者)
  19. 从女孩儿手中音乐般滑落
  20. leetcode——【猫和老鼠】

热门文章

  1. 戒烟戒的是“瘾”,EGP口含袋替烟产品尼古丁袋健康替烟
  2. 【ML】混淆矩阵(Accuracy,Precision,Recall,F1)
  3. php 实现群发表结构,利用php怎么实现一个微信公众号无限群发功能
  4. 群聊太多?三步教你用 Python 自动监听转发群消息!
  5. c语言:access函数
  6. PDF压缩在线怎么操作?这几个操作谁还不知道
  7. matlab中的折现图
  8. 单片机,51红外通信代码,详细注释【普中科技】【350行】【原创】
  9. 红帽RHCE之HTTP
  10. postman打开启动慢,原因:长时间没清理缓存,解决:删除postma缓存重启即可