Android FM模塊學習之一 FM啓動流程

  最近在學習FM模塊,FM是一個值得學習的模塊,能夠從上層看到底層。上層就是FM的按扭操做和界面顯示,從而調用到FM底層驅動來實現廣播收聽的功能。java

   看看Fm啓動流程:以下圖:git


先進入FMRadio.java類,onCreate初始化一些數據,畫出FM界面,啓動fm在onStart()方法裏啓動FMRadioService.java (調用bindToService(this, osc)方法)。api


註冊下fm設置(在設置後發送一個設置廣播,更新FMRadio類的狀態)。學習

加載初始化數據,獲取頻率地址ui

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


在bindToService(this,osc)方法中,先啓動StartService(同一個Service只onCreate一次),再啓動bindservice(這樣有個好處按返回鍵service不會走onDestroy方法)bindservice經過onBind回傳一個IBinder對象到FMRadio類的內部類ServiceConnection的onServiceConnected方法中,調用enableRadio()方法。.net

在enableRaido方法中調用FMRadio.java的isAntennaAvailable()方法進行耳機判斷,天線判斷是否可用,經過一個插入拔出廣播接收來控制的(FMRadio中的registerHeadsetListener()方法)action(Intent.ACTION_HEADSET_PLUG)3d

mHeadsetPlugged =(intent.getIntExtra("state", 0) == 1); 等於1說明耳機可用,等於0可用。orm

調用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搜索。 ---------------------    

相關文章
相關標籤/搜索