• 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搜索

  • 相关阅读:
    SpringBoot实现原理
    常见Http状态码大全
    forward(转发)和redirect(重定向)有什么区别
    1094. Car Pooling (M)
    0980. Unique Paths III (H)
    1291. Sequential Digits (M)
    0121. Best Time to Buy and Sell Stock (E)
    1041. Robot Bounded In Circle (M)
    0421. Maximum XOR of Two Numbers in an Array (M)
    0216. Combination Sum III (M)
  • 原文地址:https://www.cnblogs.com/mochaMM/p/5151842.html
Copyright © 2020-2023  润新知