转自: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()
[java] view plaincopyprint?
- <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()扬声器可用,用户设置扬声器
[java] view plaincopyprint?
- /*
- * 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);
[java] view plaincopyprint?
- 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();
[java] view plaincopyprint?
- 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)
[java] view plaincopyprint?
- <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搜索。