Android FM学习中的模块 FM启动过程
最近的研究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启动过程的更多相关文章
- Android在应用中依据包名启动另外一个APP
以下为TestIntentData工程 MainActivity如下: package cn.testintentdata; import java.util.List; import android ...
- Android应用程序组件Content Provider的启动过程源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6963418 通过前面的学习,我们知道在Andr ...
- Android系统启动流程(四)Launcher启动过程与系统启动流程
此前的文章我们学习了init进程.Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三篇 ...
- Spring Boot 学习笔记一(SpringBoot启动过程)
SpringBoot启动 Spring Boot通常有一个名为*Application的入口类,在入口类里有一个main方法,这个main方法其实就是一个标准的java应用的入口方法. 在main方法 ...
- MySQL学习笔记——MySQL5.7的启动过程(一)
MySQL的启动函数在 sql/main.cc 文件中. main.cc: extern int mysqld_main(int argc, char **argv); int main(int ar ...
- keil c51中C程序的启动过程
汇编是从org 0000h开始启动,那么keil c51是如何启动main()函数的?keil c51有一个启动程序startup.a51,它总是和c程序一起编译和链接.下面看看它和main()函数是 ...
- RN 中 Native 模块的注入过程
找到所有的模块 一般来说,只要在模块中声明 RCT_EXPORT_MODULE 即可.这是个宏,展开后是声明了一个函数,定义了两个函数,如下所示. #define RCT_EXPORT_MODULE( ...
- android菜鸟学习笔记16----Android项目打包安装过程(Run as Android Application)
右击项目名称,Run as Android Appication之后,Android项目打包安装过程: 1.打包生成.apk文件: 1)把源码中的.java文件编译生成.class文件 2)将所有的. ...
- Android 6.0启动过程具体解析
在之前的一篇文章中.从概念上学习了Andoird系统的启动过程.Android系统启动过程学习 而在这篇文章中,我们将从代码角度细致学习Android系统的启动过程,同一时候,学习Android启动过 ...
随机推荐
- ExternalInterface的简单使用方法
ExternalInterface的简单使用方法 使用ExternalInterface调用JavaScript方法-无返回值flex代码------------------<mx:Button ...
- 解决mongodb设备mongod命令不是内部或外部的命令
1:安装 去mongodb的官网http://www.mongodb.org/downloads下载32bit的包 解压后会出现下面文件 在安装的盘C:下建立mongodb目录,拷贝bin目录到该目录 ...
- 【转】Android Web Server
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://vaero.blog.51cto.com/4350852/1188602 Andr ...
- Facebook Hacker Cup 2015 Round 1--Corporate Gifting(树动态规划)
原标题:https://www.facebook.com/hackercup/problems.php?pid=759650454070547&round=344496159068801 题意 ...
- 非正确使用浮点数据由项目产生BUG讨论的问题
乘分配 当小学学会了乘法分配.详细乘法分配:并与多个两个数相乘的,他们能够把这个数字乘以,然后加入.由于一个恒定.乘法分配律也能够使用表达式的定义"(a+b)×c = a×c+b×c&quo ...
- 九度OJ 1177 查找 (模拟)
题目1177:查找 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5659 解决:1667 题目描写叙述: 读入一组字符串(待操作的),再读入一个int n记录记下来有几条命令,总共同拥有 ...
- std::string 不支持back
string s = "abc"; if ( s.back() == 'c' ) .... , 不支持back, 但是用VS2010好吧 后来发现, string的back/fr ...
- OA项目设计的能力③
1.然后来了一个,写在我们的主要要求之一,有回波数据还需要添加的方法,我们需要知道,事实上,页被传递id演出id通讯实体name,所以想要回显就是须要得到privilegeIds,假设像上一篇在jsp ...
- 2013成都邀请赛J称号||HDU4725 The Shortest Path in Nya Graph(spfa+slf最短的优化)
职务地址:HDU 4725 这题卡了好长时间了,建图倒是会建,可是不会最短路的算法优化,本以为都须要堆去优化的,打算学了堆之后再来优化.可是昨晚CF的一道题..(那题也是不优化过不了..)然后我就知道 ...
- [Aaronyang] 写给自己的WPF4.5 笔记15[AyArc诞生-WPF版本绚丽的环状图,Ay制作,AyWindow强势预览]
原文:[Aaronyang] 写给自己的WPF4.5 笔记15[AyArc诞生-WPF版本绚丽的环状图,Ay制作,AyWindow强势预览] 我的文章一定要做到对读者负责,否则就是失败的文章 -- ...