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

  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()扬声器可用,用户设置扬声器

  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.   
  47.          if (bStatus == true)  
  48.          {  
  49.             /* Put the hardware into normal mode */  
  50.            <strong> bStatus = setLowPowerMode(false);</strong>  
  51.             Log.d(LOGTAG, "setLowPowerMode done, Status :" +  bStatus);  
  52.              AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);  
  53.             if( (audioManager != null) &&(false == mPlaybackInProgress) )  
  54.             {  
  55.                Log.d(LOGTAG, "mAudioManager.setFmRadioOn = true  " );  
  56.                //audioManager.setParameters("FMRadioOn="+mAudioDevice);  
  57.                <strong>int state =  getCallState();</strong>  
  58.                if ( TelephonyManager.CALL_STATE_IDLE != getCallState() )  
  59.                {  
  60.                  <strong>fmActionOnCallState(state);</strong>  
  61.                } else {  
  62.                   <span style="color:#00CCCC;"><strong> startFM();</strong> </span>// enable FM Audio only when Call is IDLE  
  63.                }  
  64.                Log.d(LOGTAG, "mAudioManager.setFmRadioOn done  " );  
  65.             }if (mReceiver != null) {//<span style="font-family:KaiTi_GB2312;font-size:18px;">注册远程组的处理</span>  
  66. <span style="font-family:KaiTi_GB2312;">             </span> <strong>bStatus = mReceiver.registerRdsGroupProcessing(FmReceiver.FM_RX_RDS_GRP_RT_EBL|  
  67.                                                            FmReceiver.FM_RX_RDS_GRP_PS_EBL|  
  68.                                                            FmReceiver.FM_RX_RDS_GRP_AF_EBL|  
  69.                                                            FmReceiver.FM_RX_RDS_GRP_PS_SIMPLE_EBL);</strong>  
  70.                 Log.d(LOGTAG, "registerRdsGroupProcessing done, Status :" +  bStatus);  
  71.             }  
  72.             <strong>bStatus = enableAutoAF(FmSharedPreferences.getAutoAFSwitch());</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">可用自动跳转到选着的频率</span>  
  73.             Log.d(LOGTAG, "enableAutoAF done, Status :" +  bStatus);  
  74.             /* There is no internal Antenna*/  
  75.             <strong>bStatus = mReceiver.setInternalAntenna(false);/</strong>/<span style="font-family:KaiTi_GB2312;font-size:18px;">将内置天线设为0</span>  
  76.             Log.d(LOGTAG, "setInternalAntenna done, Status :" +  bStatus);  
  77.   
  78.             /* Read back to verify the internal Antenna mode*/  
  79.             readInternalAntennaAvailable();  
  80.   
  81.             startNotification();  
  82.             bStatus = true;  
  83.          }  
  84.          else  
  85.          {mReceiver = null; // as enable failed no need to disable  
  86.                               // failure of enable can be because handle  
  87.                               // already open which gets effected if  
  88.                               // we disable  
  89.             stop();  
  90.          }  
  91.       }  
  92.       return(bStatus);  
  93.    }  

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

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

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

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

                  fmActionOnCallState(state);

启动FM  startFM();

  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.          
  21.        Log.d(LOGTAG,"FM registering for registerMediaButtonEventReceiver");  
  22.        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);  
  23.        ComponentName fmRadio = new ComponentName(this.getPackageName(),  
  24.                                   FMMediaButtonIntentReceiver.class.getName());  
  25.        mAudioManager.registerMediaButtonEventReceiver(fmRadio);  
  26.        mStoppedOnFocusLoss = false;  
  27.   
  28.        if (!isSpeakerEnabled() && !mA2dpDeviceSupportInHal &&  (true == mA2dpDeviceState.isDeviceAvailable()) &&  
  29.            !isAnalogModeEnabled()  
  30.             && (true == startA2dpPlayback())) {  
  31.             mOverA2DP=true;  
  32.             Log.d(LOGTAG, "Audio source set it as A2DP");  
  33.           <strong>  AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_BT_A2DP);</strong>  
  34.        } else {  
  35.            Log.d(LOGTAG, "FMRadio: Requesting to start FM");  
  36.            //reason for resending the Speaker option is we are sending  
  37.            //ACTION_FM=1 to AudioManager, the previous state of Speaker we set  
  38.            //need not be retained by the Audio Manager.  
  39.            <strong>AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,  
  40.                                AudioSystem.DEVICE_STATE_AVAILABLE, "");</strong>//<span style="font-family:KaiTi_GB2312;font-size:18px;">Fm设备</span>  
  41.            if (isSpeakerEnabled()) {  
  42.                mSpeakerPhoneOn = true;  
  43.                Log.d(LOGTAG, "Audio source set it as speaker");  
  44.               <strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);</strong>  
  45.            } else {  
  46.                Log.d(LOGTAG, "Audio source set it as headset");  
  47.               <strong> AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);</strong>  
  48.            }  
  49.   
  50.        }  
  51.        sendRecordServiceIntent(RECORD_START);  
  52.        mPlaybackInProgress = true;  
  53.    }  


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

  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.   
  18.        int iAntenna ;  
  19.   
  20.        if (intAnt)  
  21.           iAntenna = 1;  
  22.        else  
  23.           iAntenna = 0;  
  24.   
  25.   
  26.        int re = <strong>FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna);</strong>  
  27.   
  28.        if (re == 0)  
  29.          return true;  
  30.   
  31.        return false;  
  32.    }</span>  


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

原文地址:https://www.cnblogs.com/mochaMM/p/5151842.html