转自:http://blog.csdn.net/tfslovexizi/article/details/41283743

最近在学习FM模块,FM是一个值得学习的模块,可以从上层看到底层。上层就是FM的按扭操作和界面显示,从而调用到FM底层驱动来实现广播收听的功能。

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

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

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

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

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()

[java] view plaincopyprint?
  1. <span style="font-size:18px;">private void enableRadio() {
  2. mIsScaning = false;
  3. mIsSeeking = false;
  4. mIsSearching = false;
  5. boolean bStatus = false;
  6. if (isHdmiOn()) {
  7. showDialog(DIALOG_CMD_FAILED_HDMI_ON);
  8. }else {
  9. <span style="font-family:KaiTi_GB2312;">  </span>if (mService != null) {
  10. try {
  11. if((false == mService.isFmOn()) && <strong>isAntennaAvailable()</strong>) {
  12. bStatus = mService.fmOn();
  13. if(bStatus) {
  14. tuneRadio(FmSharedPreferences.getTunedFrequency());
  15. <strong> enableRadioOnOffUI();</strong>
  16. }else {Log.e(LOGTAG, "mService.fmOn failed");
  17. mCommandFailed = CMD_FMON;
  18. if(isCallActive()) {
  19. enableRadioOnOffUI();
  20. showDialog(DIALOG_CMD_FAILED_CALL_ON);
  21. }else {
  22. showDialog(DIALOG_CMD_FAILED);
  23. }
  24. }
  25. }else {enableRadioOnOffUI();
  26. }
  27. }catch (RemoteException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }
  32. }</span>

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

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

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

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

[java] view plaincopyprint?
  1. /*
  2. * Turn ON FM: Powers up FM hardware, and initializes the FM module
  3. *                                                                                 .
  4. * @return true if fm Enable api was invoked successfully, false if the api failed.
  5. */
  6. private boolean fmOn() {
  7. boolean bStatus=false;
  8. mWakeLock.acquire(10*1000);
  9. if ( TelephonyManager.CALL_STATE_IDLE != getCallState() ) {
  10. return bStatus;
  11. }
  12. if(mReceiver == null)
  13. {
  14. try {
  15. <strong> mReceiver = new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);</strong>
  16. }
  17. catch (InstantiationException e)
  18. {
  19. throw new RuntimeException("FmReceiver service not available!");
  20. }
  21. }
  22. if (mReceiver != null)
  23. {
  24. if (isFmOn())
  25. {
  26. /* FM Is already on,*/
  27. bStatus = true;
  28. Log.d(LOGTAG, "mReceiver.already enabled");
  29. }
  30. else
  31. { // This sets up the FM radio device
  32. FmConfig config = FmSharedPreferences.getFMConfiguration();
  33. Log.d(LOGTAG, "fmOn: RadioBand   :"+ config.getRadioBand());
  34. Log.d(LOGTAG, "fmOn: Emphasis    :"+ config.getEmphasis());
  35. Log.d(LOGTAG, "fmOn: ChSpacing   :"+ config.getChSpacing());
  36. Log.d(LOGTAG, "fmOn: RdsStd      :"+ config.getRdsStd());
  37. Log.d(LOGTAG, "fmOn: LowerLimit  :"+ config.getLowerLimit());
  38. Log.d(LOGTAG, "fmOn: UpperLimit  :"+ config.getUpperLimit());
  39. <strong> bStatus = mReceiver.enable(FmSharedPreferences.getFMConfiguration());</strong>
  40. if (isSpeakerEnabled()) {
  41. setAudioPath(false);
  42. } else {setAudioPath(true);
  43. }
  44. Log.d(LOGTAG, "mReceiver.enable done, Status :" +  bStatus);
  45. }
  46. if (bStatus == true)
  47. {
  48. /* Put the hardware into normal mode */
  49. <strong> bStatus = setLowPowerMode(false);</strong>
  50. Log.d(LOGTAG, "setLowPowerMode done, Status :" +  bStatus);
  51. AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  52. if( (audioManager != null) &&(false == mPlaybackInProgress) )
  53. {
  54. Log.d(LOGTAG, "mAudioManager.setFmRadioOn = true \n" );
  55. //audioManager.setParameters("FMRadioOn="+mAudioDevice);
  56. <strong>int state =  getCallState();</strong>
  57. if ( TelephonyManager.CALL_STATE_IDLE != getCallState() )
  58. {
  59. <strong>fmActionOnCallState(state);</strong>
  60. } else {
  61. <span style="color:#00CCCC;"><strong> startFM();</strong> </span>// enable FM Audio only when Call is IDLE
  62. }
  63. Log.d(LOGTAG, "mAudioManager.setFmRadioOn done \n" );
  64. }if (mReceiver != null) {//<span style="font-family:KaiTi_GB2312;font-size:18px;">注册远程组的处理</span>
  65. <span style="font-family:KaiTi_GB2312;">             </span> <strong>bStatus = mReceiver.registerRdsGroupProcessing(FmReceiver.FM_RX_RDS_GRP_RT_EBL|
  66. FmReceiver.FM_RX_RDS_GRP_PS_EBL|
  67. FmReceiver.FM_RX_RDS_GRP_AF_EBL|
  68. FmReceiver.FM_RX_RDS_GRP_PS_SIMPLE_EBL);</strong>
  69. Log.d(LOGTAG, "registerRdsGroupProcessing done, Status :" +  bStatus);
  70. }
  71. <strong>bStatus = enableAutoAF(FmSharedPreferences.getAutoAFSwitch());</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">可用自动跳转到选着的频率</span>
  72. Log.d(LOGTAG, "enableAutoAF done, Status :" +  bStatus);
  73. /* There is no internal Antenna*/
  74. <strong>bStatus = mReceiver.setInternalAntenna(false);/</strong>/<span style="font-family:KaiTi_GB2312;font-size:18px;">将内置天线设为0</span>
  75. Log.d(LOGTAG, "setInternalAntenna done, Status :" +  bStatus);
  76. /* Read back to verify the internal Antenna mode*/
  77. readInternalAntennaAvailable();
  78. startNotification();
  79. bStatus = true;
  80. }
  81. else
  82. {mReceiver = null; // as enable failed no need to disable
  83. // failure of enable can be because handle
  84. // already open which gets effected if
  85. // we disable
  86. stop();
  87. }
  88. }
  89. return(bStatus);
  90. }

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

[java] view plaincopyprint?
  1. private boolean setAudioPath(boolean analogMode) {
  2. if (mReceiver == null) {
  3. return false;
  4. }
  5. if (isAnalogModeEnabled() == analogMode) {
  6. Log.d(LOGTAG,"Analog Path already is set to "+analogMode);
  7. return false;
  8. }
  9. if (!isAnalogModeSupported()) {
  10. Log.d(LOGTAG,"Analog Path is not supported ");
  11. return false;
  12. }
  13. if (SystemProperties.getBoolean("hw.fm.digitalpath",false)) {
  14. return false;
  15. }
  16. boolean state =<strong> mReceiver.setAnalogMode(analogMode);</strong>
  17. if (false == state) {
  18. Log.d(LOGTAG, "Error in toggling analog/digital path " + analogMode);
  19. return false;
  20. }
  21. misAnalogPathEnabled = analogMode;
  22. return true;
  23. }

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

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

fmActionOnCallState(state);

启动FM  startFM();

[java] view plaincopyprint?
  1. private void startFM(){
  2. Log.d(LOGTAG, "In startFM");
  3. if(true == mAppShutdown) { // not to send intent to AudioManager in Shutdown
  4. return;
  5. }
  6. if (isCallActive()) { // when Call is active never let audio playback
  7. mResumeAfterCall = true;
  8. return;
  9. }
  10. mResumeAfterCall = false;
  11. if ( true == mPlaybackInProgress ) // no need to resend event
  12. return;
  13. AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  14. int granted = audioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
  15. AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
  16. if(granted != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
  17. Log.d(LOGTAG, "audio focuss couldnot be granted");
  18. return;
  19. }
  20. Log.d(LOGTAG,"FM registering for registerMediaButtonEventReceiver");
  21. mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  22. ComponentName fmRadio = new ComponentName(this.getPackageName(),
  23. FMMediaButtonIntentReceiver.class.getName());
  24. mAudioManager.registerMediaButtonEventReceiver(fmRadio);
  25. mStoppedOnFocusLoss = false;
  26. if (!isSpeakerEnabled() && !mA2dpDeviceSupportInHal &&  (true == mA2dpDeviceState.isDeviceAvailable()) &&
  27. !isAnalogModeEnabled()
  28. && (true == startA2dpPlayback())) {
  29. mOverA2DP=true;
  30. Log.d(LOGTAG, "Audio source set it as A2DP");
  31. <strong>  AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_BT_A2DP);</strong>
  32. } else {
  33. Log.d(LOGTAG, "FMRadio: Requesting to start FM");
  34. //reason for resending the Speaker option is we are sending
  35. //ACTION_FM=1 to AudioManager, the previous state of Speaker we set
  36. //need not be retained by the Audio Manager.
  37. <strong>AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
  38. AudioSystem.DEVICE_STATE_AVAILABLE, "");</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">Fm设备</span>
  39. if (isSpeakerEnabled()) {
  40. mSpeakerPhoneOn = true;
  41. Log.d(LOGTAG, "Audio source set it as speaker");
  42. <strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);</strong>
  43. } else {
  44. Log.d(LOGTAG, "Audio source set it as headset");
  45. <strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);</strong>
  46. }
  47. }
  48. sendRecordServiceIntent(RECORD_START);
  49. mPlaybackInProgress = true;
  50. }

设置耳机等可以接受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)

[java] view plaincopyprint?
  1. <span style="font-size:18px;"> /*==============================================================
  2. FUNCTION:  setInternalAntenna
  3. ==============================================================*/
  4. /**
  5. *    Returns true if successful, false otherwise
  6. *
  7. *    <p>
  8. *    This method sets internal antenna type to true/false
  9. *
  10. *    @param intAntenna true is Internal antenna is present
  11. *
  12. *    <p>
  13. *    @return    true/false
  14. */
  15. public boolean setInternalAntenna(boolean intAnt)
  16. {
  17. int iAntenna ;
  18. if (intAnt)
  19. iAntenna = 1;
  20. else
  21. iAntenna = 0;
  22. int re = <strong>FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna);</strong>
  23. if (re == 0)
  24. return true;
  25. return false;
  26. }</span>

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

转载于:https://www.cnblogs.com/mochaMM/p/5151842.html

Android FM模块学习之一 FM启动流程相关推荐

  1. LIteOS学习笔记-7LiteOS启动流程与编译流程

    LIteOS学习笔记-7LiteOS启动流程与编译流程 LiteOS启动流程 1. 启动方式 2. 启动流程 硬件初始化 内核初始化 调试串口初始化 尝试进行网络连接 启动任务调度 LiteOS编译流 ...

  2. android fm模块学习,AndroidFM模块学习之5关闭FM流程

    AndroidFM模块学习之五关闭FM流程 前一阵子简单描述了一些关于FM开启.录音和搜索的流程,浅析了一下各个类的源码,接下来就是关闭FM了,FM模块的学习就告一段落了,希望这阵子的整理能对大家在F ...

  3. Android FM模块学习之二 FM搜索频率流程

    上一篇大概分析了一下FM启动流程,若不了解Fm启动流程的,可以去打开前面的链接先了解FM启动流程,接下来我们简单分析一下FM的搜索频率流程. 在了解源码之前,我们先看一下流程图: 其实从图中可以看到, ...

  4. Android FM模块学习之四源码解析(一)

    前一章我们了解了FM手动调频,接下来我们要分析FM模块用到的源码.此源码是基于高通平台的,别的平台都大同小异,只不过是平台自己作了些小改动而已. 首先要看的当然是主activity, FMRadio. ...

  5. Android FM 模块学习之四 源码解析(1)

    前一章我们了解了FM手动调频,接下来我们要分析FM模块用到的源码.此源码是基于高通平台的,别的平台都大同小异,只不过是平台自己作了些小改动而已. 首先要看的当然是主activity, FMRadio. ...

  6. Android FM模块学习之四源码分析(五)

    前几章我们分析了FM模块的几个主要的类文件,今天要分析的是:FMTransceiver.java public class FmTransceiver {/* Primary FM States :* ...

  7. Android FM模块学习之四源码学习(2)

    前几章我们分析了FM模块的几个主要的类文件,今天要分析的是:FMTransceiver.java   // 某些工程中名称为FMRadioService.java public class FmTra ...

  8. Android 10.0 系统服务之ActivityMnagerService-AMS启动流程-[Android取经之路]

    摘要:上一节我们讲完了SystemServer的启动过程,这一节接着上一节的步骤,来讲解ActivityManagerService的启动过程. ActivityManagerService简称AMS ...

  9. ASP.NET Core MVC 源码学习:MVC 启动流程详解

    前言 在 上一篇 文章中,我们学习了 ASP.NET Core MVC 的路由模块,那么在本篇文章中,主要是对 ASP.NET Core MVC 启动流程的一个学习. ASP.NET Core 是新一 ...

最新文章

  1. object.create()
  2. Maven多模块项目使用MyBatis Generator
  3. 使用指定glibc编译程序
  4. 下次偶转贴贴子时得加上转贴才行~~~
  5. 【数学分析笔记01】平均值不等式证明
  6. Tensorflow2.0之FGSM
  7. autoCAD 使用选择集
  8. 计算机无法添加本地策略组,电脑打不开本地组策略编辑器,求破~!
  9. (二)C语言开发工具
  10. Google开源Live Transcribe的语音引擎
  11. 酪氨酸激酶的抑制剂——白血病的靶向研究
  12. STM32理论 —— 综述、GPIO
  13. xss绕过字符过滤_xss绕过过滤之方法
  14. GateWay坑——context-path
  15. 睡觉少对孩子影响很大肚子变胖记忆受损
  16. 模型稳定度指标PSI与IV
  17. IOST节点搭建【私链】
  18. OSChina 周四乱弹 ——前两天BUG还没改完啊?老子不改了!
  19. [网络电话]Android CSipSimple开发实例
  20. shell银行账户管理程序_如何在德国设立银行账户?德国银行卡比较和解析

热门文章

  1. 如何使用XenServer使用本地ISO镜像
  2. evernote使用推荐
  3. 使用 SQL Server Mobile 创建移动应用程序
  4. 带你走进Kaggle Kernels(内附视频讲解)
  5. Asp.net SignalR 应用并实现群聊功能 开源代码
  6. css基础 设置链接颜色
  7. 【原创】Kakfa utils源代码分析(二)
  8. rails 3 使用 cucumber 和rspec 進行 測試
  9. get传递中文产生乱码的解决方式汇总
  10. Java---实现运行任意目录下class中加了@MyTest的空参方法(实现图形界面)