Android FM模块学习之一 FM启动流程

转自: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搜索

时间: 2024-10-10 05:24:40

Android FM模块学习之一 FM启动流程的相关文章

Android FM模块学习之三 FM手动调频

前一章我们学习了FM的自动调频,接下来我们就看看FM手动调频是如何进行的.如果不清楚FM自动调频的过程,请打开超链接查看FM搜索频率流程. 首先来看一下流程图: 2.滑动刻度盘HorizontalNumberPicker控件在监听事件里使用方法valueToFrequency(newVal) 1.长按左右箭头居中的频率字符串,弹出FrequencyPickerDialog调频对话框确定调用tuneRadio(frequency)调频. 获取到频率 protected int valueToFre

Android FM模块学习之四源码解析(二)

上一章我们了解了FM主activity:FMRadio.java,若没查看的,请打开链接Android FM模块学习之四源码解析(一) 查看fmradio.java源码注释.接下来我们来看看FM重要的一个类:FMRadioService.java 由上一章我们已经知道,打开FM时,在OnStart函数中会bindToService来开启服务, public boolean bindToService(Context context, ServiceConnection callback) { L

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

上一篇大概分析了一下FM启动流程,若不了解Fm启动流程的,能够去打开前面的链接先了解FM启动流程,接下来我们简单分析一下FM的搜索频率流程. 在了解源代码之前.我们先看一下流程图: 事实上从图中能够看到,实现搜索频率的功能是在底层CPP文件.java层仅仅操作和更新一些界面(GUI),Java调用JNI实现功能.Java app基本核心,通过方法回调实现a类和b类方法.b类调a类方法信息交互相互控制融为一体.App实现一些JNI接口终于实现核心功能是cpp文件,最后通过Service类(耗时操作

Android FM模块学习之二 FM搜索频道

最近在学习FM模块,FM是一个值得学习的模块,可以从上层看到底层.上层就是FM的按扭操作和界面显示,从而调用到FM底层驱动来实现广播收听的功能. 看看FM启动流程:如下图: 先进入FMRadio.java类,onCreate初始化一些数据,画出FM界面,启动fm在onStart()方法里启动FMRadioService.java (调用bindToService(this, osc)方法). 注册下fm设置(在设置后发送一个设置广播,更新FMRadio类的状态). 加载初始化数据,获取频率地址

Android FM模块学习之四源码解析(三)

由于最近一直忙项目,没有时间来更新文档,今天抽空来写一点,希望大家可以学习使用! 这一章当然还是来分析FM模块的源码.FmReceiver.java publicFmReceiver(String devicePath,FmRxEvCallbacksAdaptor callback) throwsInstantiationException { mControl = new FmRxControls(); mRxEvents = new FmRxEventListner(); //registe

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

前一章我们了解了FM手动调频,接下来我们要分析FM模块用到的源码.此源码是基于高通平台的,别的平台都大同小异,只不过是平台自己作了些小改动而已. 首先要看的当然是主activity, FMRadio.java fmradio类启动FMRadioService.java类调用FmSharedPreferences类进行存储数据,PresetStation调整频率 setVolumeControlStream(AudioManager.STREAM_MUSIC);音乐回放即媒体音量 LoadedDa

Android FM模块学习之四源码分析(3)

接着看FM模块的其他几个次要的类的源码.这样来看FM上层的东西不是太多. 请看android\vendor\qcom\opensource\fm\fmapp2\src\com\caf\fmradio\Settings.java protected void onCreate(BundlesavedInstanceState) 从FMRadio.java用使用Intent跳转携带参数过来,在onCreate获取携带数据. protected void onCreate(Bundle savedIn

Android FM模块学习之源码分析(六)

现在是2015年1月啦,得改口说去年了,去年抽时间整理了一些FM模块的主要源码类的东西,今年再整理一下几个次要的类的源码.这样来看FM上层的东西不是太多. 请看android\vendor\qcom\opensource\fm\fmapp2\src\com\caf\fmradio\Settings.java protected void onCreate(BundlesavedInstanceState) 从FMRadio.java用使用Intent跳转携带参数过来,在onCreate获取携带数

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

前几章我们分析了FM模块的几个主要的类文件,今天要分析的是:FMTransceiver.java   // 某些工程中名称为FMRadioService.java public class FmTransceiver { /* Primary FM States : * FM will be in one of the 4 states at any point of time * '0' - FMState_Turned_Off * '1' - FMState_Rx_Turned_On * '