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

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

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

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

Android FM模块学习之一 FM启动流程
注册下fm设置(在设置后发送一个设置广播,更新FMRadio类的状态)。

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

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

newPresetStation("",FmSharedPreferences.getTunedFrequency());

Android FM模块学习之一 FM启动流程
在bindToService(this,osc)方法中,先启动StartService(同一个Service只onCreate一次),再启动bindservice(这样有个好处按返回键service不会走onDestroy方法)bindservice通过onBind回传一个IBinder对象到FMRadio类的内部类ServiceConnection的onServiceConnected方法中,调用enableRadio()方法。

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

在enableRaido方法中调用FMRadio.java的isAntennaAvailable()方法进行耳机判断,天线判断是否可用,通过一个插入拔出广播接收来控制的(FMRadio中的registerHeadsetListener()方法)action(Intent.ACTION_HEADSET_PLUG)

mHeadsetPlugged =(intent.getIntExtra("state", 0) == 1); 等于1说明耳机可用,等于0可用。

调用FmRadio方法FmOn  (mService.fmOn())

界面可用enableRadioOnOffUI()

    private void enableRadio() {
          mIsScaning = false;
          mIsSeeking = false;
          mIsSearching = false;
          boolean bStatus = false;
          if (isHdmiOn()) {
              showDialog(DIALOG_CMD_FAILED_HDMI_ON);
          }else {
            if (mService != null) {
                 try {
                    if((false == mService.isFmOn()) && isAntennaAvailable()</strong>) {
                        bStatus = mService.fmOn();
                        if(bStatus) {
                           tuneRadio(FmSharedPreferences.getTunedFrequency());
                           enableRadioOnOffUI();
                        }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();
                 }
              }
          }
       }


在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 {
                mReceiver = new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);
             }
             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());
                bStatus = mReceiver.enable(FmSharedPreferences.getFMConfiguration());
                if (isSpeakerEnabled()) {
                    setAudioPath(false);
                } else {setAudioPath(true);
                }
                Log.d(LOGTAG, "mReceiver.enable done, Status :" +  bStatus);
             }
     
             if (bStatus == true)
             {
                /* Put the hardware into normal mode */
                bStatus = setLowPowerMode(false);
                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);
                   int state =  getCallState();
                   if ( TelephonyManager.CALL_STATE_IDLE != getCallState() )
                   {
                     fmActionOnCallState(state);
                   } else {
                       startFM();// enable FM Audio only when Call is IDLE
                   }
                   Log.d(LOGTAG, "mAudioManager.setFmRadioOn done \n" );
                }if (mReceiver != null) {//<注册远程组的处理
     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);
                    Log.d(LOGTAG, "registerRdsGroupProcessing done, Status :" +  bStatus);
                }
               bStatus = enableAutoAF(FmSharedPreferences.getAutoAFSwitch());//可用自动跳转到选着的频率
                Log.d(LOGTAG, "enableAutoAF done, Status :" +  bStatus);
                /* There is no internal Antenna*/
                bStatus = mReceiver.setInternalAntenna(false);//将内置天线设为0
                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 = mReceiver.setAnalogMode(analogMode);
            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");
              AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_BT_A2DP);
           } 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.
               AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
                                   AudioSystem.DEVICE_STATE_AVAILABLE, "");//<Fm设备
               if (isSpeakerEnabled()) {
                   mSpeakerPhoneOn = true;
                   Log.d(LOGTAG, "Audio source set it as speaker");
                   AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_SPEAKER);
               } else {
                   Log.d(LOGTAG, "Audio source set it as headset");
                   AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, AudioSystem.FORCE_NONE);
               }
     
           }
           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)


       /**
       *    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 = FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna);
     
           if (re == 0)
             return true;
     
           return false;
       }


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

转载于:https://my.oschina.net/u/920274/blog/2998268