最近的研究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. 怎么确定你的CPU是否支持64位虚拟化

    http://www.grc.com/securable.htm 第一个64位表示你的电脑最多支持多少位的系统,32或者64. 第二个表示你的硬件是否支持DEP?Yes,支持.No,不支持.OFF,表 ...

  2. C++习题 对象数组输入与输出

    Description 建立一个对象数组,内放n(n<10)个学生的数据(学号.成绩),用指针指向数组首元素,输出第奇数(1,3,5,7)个学生的数据. Input n和n个学生的学号.成绩 O ...

  3. ./startup.sh: Permission denied

    今天在Linux上部署项目,之前报过这个错误,通过下面方式攻克了.如今发出来备份一下: LINUX权限-bash: ./startup.sh: Permission denied 运行./startu ...

  4. iOS编程之前

    iOS编程之前 更新:帖子已经重新被更新过,以便能更好的兼容Xcode 5和iOS 7.       至今为止,已经超过6000位读者加入了这个iOS免费教程.首先,我要感谢这些加入我们社区的朋友.在 ...

  5. 探索C/C++大数快(自然数)模板

    本文fcbruce个人原创整理.转载请注明出处http://blog.csdn.net/u012965890/article/details/40432511,谢谢. 我们知道在C/C++中int型可 ...

  6. Android ELF文件格式

    最近一直在学习elf相关信息.一个小总结,这里记录,也方便以后查阅. ELF是类Unix类系统,当然也包含Android系统上的可运行文件格式(也包含.so和.o类文件). 能够理解为Android系 ...

  7. myEclipse项目部署按钮失效了,怎么办?

    myEclipse项目部署按钮失效了,按了以后没反应,怎么办? 步骤如下: 1.首先关闭MyEclipse. 2.然后删除Workspaces目录(存放您MyEclipse项目的地方)下的 " ...

  8. 配置Tomcat出现Unsupported major.minor version 51.0

    在配置tomcat时,配置好jdk1.6,下载的tomcat8.0,结果执行start-up.bat,总是一闪而过,网上查了大量的资料,都说是可能是jdk没配置好,但实际上jdk的环境变量设置正常,后 ...

  9. IOS-QQ登陆之苹果程序流程

    1.新建项目,通过main函数循环执行代码,直到应用被关闭. 2.点击项目,建立storyboard文件,并在info文件夹中指定第一个storyboard文件 3.建立Controller文件. 组 ...

  10. 【C++基金会 06】explictkeyword

    C++提供keywordexplicit,你应该不能阻止的转换构造隐式转换发生的同意.声明explicit的构造不能在一个隐式转换使用. 1.演示样例 我们先来看一段演示样例代码: class A { ...