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