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

   最近在学习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()


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

在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 {
           <strong> mReceiver = new FmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);</strong>
         }
         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());
           <strong> bStatus = mReceiver.enable(FmSharedPreferences.getFMConfiguration());</strong>
            if (isSpeakerEnabled()) {
                setAudioPath(false);
            } else {setAudioPath(true);
            }
            Log.d(LOGTAG, "mReceiver.enable done, Status :" +  bStatus);
         }

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

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

<span style="font-size:18px;"> /*==============================================================
   FUNCTION:  setInternalAntenna
   ==============================================================*/
   /**
   *    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 = <strong>FmReceiverJNI.setControlNative (sFd, V4L2_CID_PRIVATE_TAVARUA_ANTENNA, iAntenna);</strong>

       if (re == 0)
         return true;

       return false;
   }</span>

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



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值