最近的研究FM模,FM是一家值我正在学习模块。什么可以从上层中可以看出。

上层是FM按钮的操作和界面显示,因此调用到FM来实现广播收听的功能。

看看Fm启动流程:例如以下图:

先进入FMRadio.java类,onCreate初始化一些数据。画出FM界面。启动fm在onStart()方法里启动FMRadioService.java (调用bindToService(this, osc)方法)。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGZzbG92ZXhpemk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

注冊下fm设置(在设置后发送一个设置广播,更新FMRadio类的状态)。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGZzbG92ZXhpemk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

载入初始化数据,获取频率地址

newPresetStation("",FmSharedPreferences.getTunedFrequency());

在bindToService(this,osc)方法中,先启动StartService(同一个Service仅仅onCreate一次),再启动bindservice(这样有个优点按返回键service不会走onDestroy方法)bindservice通过onBind回传一个IBinder对象到FMRadio类的内部类ServiceConnection的onServiceConnected方法中,调用enableRadio()方法。

在enableRaido方法中调用FMRadio.java的isAntennaAvailable()方法进行耳机推断,天线推断是否可用。通过一个插入拔出广播接收来控制的(FMRadio中的registerHeadsetListener()方法)action(Intent.ACTION_HEADSET_PLUG)

mHeadsetPlugged =(intent.getIntExtra("state", 0) == 1); 等于1说明耳机可用,等于0可用。

调用FmRadio方法FmOn  (mService.fmOn())

界面可用enableRadioOnOffUI()

<span style="font-size:18px;">private void enableRadio() {
mIsScaning = false;
mIsSeeking = false;
mIsSearching = false;
boolean bStatus = false;
if (isHdmiOn()) {
showDialog(DIALOG_CMD_FAILED_HDMI_ON);
}else {
<span style="font-family:KaiTi_GB2312;"> </span>if (mService != null) {
try {
if((false == mService.isFmOn()) && <strong>isAntennaAvailable()</strong>) {
bStatus = mService.fmOn();
if(bStatus) {
tuneRadio(FmSharedPreferences.getTunedFrequency());
<strong> enableRadioOnOffUI();</strong>
}else {Log.e(LOGTAG, "mService.fmOn failed");
mCommandFailed = CMD_FMON;
if(isCallActive()) {
enableRadioOnOffUI();
showDialog(DIALOG_CMD_FAILED_CALL_ON);
}else {
showDialog(DIALOG_CMD_FAILED);
}
}
}else {enableRadioOnOffUI();
}
}catch (RemoteException e) {
e.printStackTrace();
}
}
}
}</span>

在FMRadioService.java的fmOn()方法中初始化FmReceiver的引用mReceiver = newFmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);

取出设置保存的地区频率的属性  FmConfig config =FmSharedPreferences.getFMConfiguration();

真正接受fm声音在  bStatus =mReceiver.enable(FmSharedPreferences.getFMConfiguration());

isSpeakerEnabled()扬声器可用,用户设置扬声器

/*
* Turn ON FM: Powers up FM hardware, and initializes the FM module
* .
* @return true if fm Enable api was invoked successfully, false if the api failed.
*/
private boolean fmOn() {
boolean bStatus=false;
mWakeLock.acquire(10*1000);
if ( TelephonyManager.CALL_STATE_IDLE != getCallState() ) {
return bStatus;
}
if(mReceiver == null)
{
try {
<strong> mReceiver = new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);</strong>
}
catch (InstantiationException e)
{
throw new RuntimeException("FmReceiver service not available!");
}
}
if (mReceiver != null)
{
if (isFmOn())
{
/* FM Is already on,*/
bStatus = true;
Log.d(LOGTAG, "mReceiver.already enabled");
}
else
{ // This sets up the FM radio device
FmConfig config = FmSharedPreferences.getFMConfiguration();
Log.d(LOGTAG, "fmOn: RadioBand :"+ config.getRadioBand());
Log.d(LOGTAG, "fmOn: Emphasis :"+ config.getEmphasis());
Log.d(LOGTAG, "fmOn: ChSpacing :"+ config.getChSpacing());
Log.d(LOGTAG, "fmOn: RdsStd :"+ config.getRdsStd());
Log.d(LOGTAG, "fmOn: LowerLimit :"+ config.getLowerLimit());
Log.d(LOGTAG, "fmOn: UpperLimit :"+ config.getUpperLimit());
<strong> bStatus = mReceiver.enable(FmSharedPreferences.getFMConfiguration());</strong>
if (isSpeakerEnabled()) {
setAudioPath(false);
} else {setAudioPath(true);
}
Log.d(LOGTAG, "mReceiver.enable done, Status :" + bStatus);
} if (bStatus == true)
{
/* Put the hardware into normal mode */
<strong> bStatus = setLowPowerMode(false);</strong>
Log.d(LOGTAG, "setLowPowerMode done, Status :" + bStatus);
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if( (audioManager != null) &&(false == mPlaybackInProgress) )
{
Log.d(LOGTAG, "mAudioManager.setFmRadioOn = true \n" );
//audioManager.setParameters("FMRadioOn="+mAudioDevice);
<strong>int state = getCallState();</strong>
if ( TelephonyManager.CALL_STATE_IDLE != getCallState() )
{
<strong>fmActionOnCallState(state);</strong>
} else {
<span style="color:#00CCCC;"><strong> startFM();</strong> </span>// enable FM Audio only when Call is IDLE
}
Log.d(LOGTAG, "mAudioManager.setFmRadioOn done \n" );
}if (mReceiver != null) {//<span style="font-family:KaiTi_GB2312;font-size:18px;">注冊远程组的处理</span>
<span style="font-family:KaiTi_GB2312;"> </span> <strong>bStatus = mReceiver.registerRdsGroupProcessing(FmReceiver.FM_RX_RDS_GRP_RT_EBL|
FmReceiver.FM_RX_RDS_GRP_PS_EBL|
FmReceiver.FM_RX_RDS_GRP_AF_EBL|
FmReceiver.FM_RX_RDS_GRP_PS_SIMPLE_EBL);</strong>
Log.d(LOGTAG, "registerRdsGroupProcessing done, Status :" + bStatus);
}
<strong>bStatus = enableAutoAF(FmSharedPreferences.getAutoAFSwitch());</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">可用自己主动跳转到选着的频率</span>
Log.d(LOGTAG, "enableAutoAF done, Status :" + bStatus);
/* There is no internal Antenna*/
<strong>bStatus = mReceiver.setInternalAntenna(false);/</strong>/<span style="font-family:KaiTi_GB2312;font-size:18px;">将内置天线设为0</span>
Log.d(LOGTAG, "setInternalAntenna done, Status :" + bStatus); /* Read back to verify the internal Antenna mode*/
readInternalAntennaAvailable(); startNotification();
bStatus = true;
}
else
{mReceiver = null; // as enable failed no need to disable
// failure of enable can be because handle
// already open which gets effected if
// we disable
stop();
}
}
return(bStatus);
}

设置铃声路径  boolean state =mReceiver.setAnalogMode(analogMode);

   private boolean setAudioPath(boolean analogMode) {

        if (mReceiver == null) {
return false;
}
if (isAnalogModeEnabled() == analogMode) {
Log.d(LOGTAG,"Analog Path already is set to "+analogMode);
return false;
}
if (!isAnalogModeSupported()) {
Log.d(LOGTAG,"Analog Path is not supported ");
return false;
}
if (SystemProperties.getBoolean("hw.fm.digitalpath",false)) {
return false;
} boolean state =<strong> mReceiver.setAnalogMode(analogMode);</strong>
if (false == state) {
Log.d(LOGTAG, "Error in toggling analog/digital path " + analogMode);
return false;
}
misAnalogPathEnabled = analogMode;
return true;
}

analogMode模拟设置低功率  bStatus = setLowPowerMode(false);

电话不在闲置状太下 int state = getCallState();

fmActionOnCallState(state);

启动FM  startFM();

private void startFM(){
Log.d(LOGTAG, "In startFM");
if(true == mAppShutdown) { // not to send intent to AudioManager in Shutdown
return;
}
if (isCallActive()) { // when Call is active never let audio playback
mResumeAfterCall = true;
return;
}
mResumeAfterCall = false;
if ( true == mPlaybackInProgress ) // no need to resend event
return;
AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
int granted = audioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
if(granted != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.d(LOGTAG, "audio focuss couldnot be granted");
return;
} Log.d(LOGTAG,"FM registering for registerMediaButtonEventReceiver");
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
ComponentName fmRadio = new ComponentName(this.getPackageName(),
FMMediaButtonIntentReceiver.class.getName());
mAudioManager.registerMediaButtonEventReceiver(fmRadio);
mStoppedOnFocusLoss = false; if (!isSpeakerEnabled() && !mA2dpDeviceSupportInHal && (true == mA2dpDeviceState.isDeviceAvailable()) &&
!isAnalogModeEnabled()
&& (true == startA2dpPlayback())) {
mOverA2DP=true;
Log.d(LOGTAG, "Audio source set it as A2DP");
<strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_BT_A2DP);</strong>
} else {
Log.d(LOGTAG, "FMRadio: Requesting to start FM");
//reason for resending the Speaker option is we are sending
//ACTION_FM=1 to AudioManager, the previous state of Speaker we set
//need not be retained by the Audio Manager.
<strong>AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
AudioSystem.DEVICE_STATE_AVAILABLE, "");</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">Fm设备</span>
if (isSpeakerEnabled()) {
mSpeakerPhoneOn = true;
Log.d(LOGTAG, "Audio source set it as speaker");
<strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);</strong>
} else {
Log.d(LOGTAG, "Audio source set it as headset");
<strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);</strong>
} }
sendRecordServiceIntent(RECORD_START);
mPlaybackInProgress = true;
}

设置耳机等能够接受fm声音

AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,AudioSystem.FORCE_NONE);

Fm设备可用 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,

AudioSystem.DEVICE_STATE_AVAILABLE, "");

注冊远程组的处理

bStatus = mReceiver.registerRdsGroupProcessing(FmReceiver.FM_RX_RDS_GRP_RT_EBL|

FmReceiver.FM_RX_RDS_GRP_PS_EBL|

FmReceiver.FM_RX_RDS_GRP_AF_EBL|

FmReceiver.FM_RX_RDS_GRP_PS_SIMPLE_EBL);

可用自己主动跳转到选着的频率  bStatus =enableAutoAF(FmSharedPreferences.getAutoAFSwitch());

将内置天线设为0 FmTransceiver.java

mReceiver.setInternalAntenna(false)

FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA,iAntenna)

<span style="font-size:18px;"> /*==============================================================
FUNCTION: setInternalAntenna
==============================================================*/
/**
* Returns true if successful, false otherwise
*
* <p>
* This method sets internal antenna type to true/false
*
* @param intAntenna true is Internal antenna is present
*
* <p>
* @return true/false
*/
public boolean setInternalAntenna(boolean intAnt)
{ int iAntenna ; if (intAnt)
iAntenna = 1;
else
iAntenna = 0; int re = <strong>FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna);</strong> if (re == 0)
return true; return false;
}</span>

好,到此为止,FM的启动工作基本上就完毕了。接下来就须要去搜索频道了,兴许会继续分析FM搜索

Android FM学习中的模块 FM启动过程的更多相关文章

  1. Android在应用中依据包名启动另外一个APP

    以下为TestIntentData工程 MainActivity如下: package cn.testintentdata; import java.util.List; import android ...

  2. Android应用程序组件Content Provider的启动过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6963418 通过前面的学习,我们知道在Andr ...

  3. Android系统启动流程(四)Launcher启动过程与系统启动流程

    此前的文章我们学习了init进程.Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三篇 ...

  4. Spring Boot 学习笔记一(SpringBoot启动过程)

    SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...

  5. MySQL学习笔记——MySQL5.7的启动过程(一)

    MySQL的启动函数在 sql/main.cc 文件中. main.cc: extern int mysqld_main(int argc, char **argv); int main(int ar ...

  6. keil c51中C程序的启动过程

    汇编是从org 0000h开始启动,那么keil c51是如何启动main()函数的?keil c51有一个启动程序startup.a51,它总是和c程序一起编译和链接.下面看看它和main()函数是 ...

  7. RN 中 Native 模块的注入过程

    找到所有的模块 一般来说,只要在模块中声明 RCT_EXPORT_MODULE 即可.这是个宏,展开后是声明了一个函数,定义了两个函数,如下所示. #define RCT_EXPORT_MODULE( ...

  8. android菜鸟学习笔记16----Android项目打包安装过程(Run as Android Application)

    右击项目名称,Run as Android Appication之后,Android项目打包安装过程: 1.打包生成.apk文件: 1)把源码中的.java文件编译生成.class文件 2)将所有的. ...

  9. Android 6.0启动过程具体解析

    在之前的一篇文章中.从概念上学习了Andoird系统的启动过程.Android系统启动过程学习 而在这篇文章中,我们将从代码角度细致学习Android系统的启动过程,同一时候,学习Android启动过 ...

随机推荐

  1. Aix db2 经user a using b连接时报SQL30082N Security processing failed with reason &quot;42&quot;

    db2inst1登录 输入实例文件夹:/opt/ibm/db2/V9.7/instance 关闭实例:db2stop 更新示例:./db2iupdt db2inst1 启动实例:db2start 再次 ...

  2. 位图像素的颜色 携程编程大赛hdu

    位图像素的颜色 Time Limit: 2000/1000 MS (Java/Others)    MemoryLimit: 32768/32768 K (Java/Others) Total Sub ...

  3. retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1 SECONDS)

    [root@qa bin]# hadoop fs -ls / Warning: $HADOOP_HOME is deprecated. 14/07/29 13:25:35 INFO ipc.Clien ...

  4. CFileDialog 使用简单介绍

    CFileDialog使用文件选择对话框:首先构造一个对象,并提供一个相应的参数,构造函数原型例如,下面的: CFileDialog::CFileDialog( BOOL bOpenFileDialo ...

  5. ef添加字段

    先在实体类里添加字段 ,然后执行 Add-Migration updateNumberOfLikes Update-Database -Verbose

  6. mysql声明摘要

    前一段时间,和学生参加该项目的最终完成,主要的项目是做一个报告,它涉及到很多sql声明,因此,采取下一个汇总. 一.基金会 1.数据库相关的命令 a>.创建数据库 CREATE DATABASE ...

  7. JFinal 的源代码超具体的分析DB+ActiveRecord

    我记得有人告诉我."面试一下spring源代码.看ioc.aop源代码"那为什么要看这些开源框架的源代码呢,事实上非常多人都是"应急式"的去读.就像读一篇文章一 ...

  8. 一天JavaScript示例-点击图片显示大图片添加鼠标

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  9. [Unity3d]定义自己的鼠标

    [Unity3d]自己定义鼠标 我们在用unity3d开发自己的游戏的时候.自己定义游戏中的鼠标也是常常要用到的.那我就得学学.事实上原理非常easy,先将鼠标给隐藏,然后在鼠标的位置上画出一个自己定 ...

  10. php中国的垃圾问题

    header这条线加,这是解决中国乱码的问题. 版权声明:本文博主原创文章,博客,未经同意不得转载.