Android FM模块学习之四源码解析(二)

上一章我们了解了FM主activity:FMRadio.java,若没查看的,请打开链接Android FM模块学习之四源码解析(一)

查看fmradio.java源码注释。接下来我们来看看FM重要的一个类:FMRadioService.java

由上一章我们已经知道,打开FM时,在OnStart函数中会bindToService来开启服务,

    public  boolean bindToService(Context context, ServiceConnection callback) {
          Log.e(LOGTAG, "bindToService: Context with serviceconnection callback");
          context.startService(new Intent(context, FMRadioService.class));
          ServiceBinder sb = new ServiceBinder(callback);
          sConnectionMap.put(context, sb);
          return context.bindService((new Intent()).setClass(context,
                                                             FMRadioService.class), sb, 0);
       }

开启了服务,就会去做一些FM的操作和响应。我们进入到类FMRadioSerivce.java中

在publicvoid onCreate() 方法里初始化数据

mPrefs = new FmSharedPreferences(this);初始化存取数据

 

电话监听
TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
      tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE |
                                       PhoneStateListener.LISTEN_DATA_ACTIVITY);

保持CPU 运转,屏幕和键盘灯有可能是关闭的

    PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
          mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
          mWakeLock.setReferenceCounted(false);
3495fa210bcf2b873b6fa72b465d3994ce3.jpg

注册屏幕是否开启

     registerScreenOnOffListener();

      注册耳机

     registerHeadsetListener();

     registerSleepExpired();

     registerRecordTimeout();

     registerDelayedServiceStop();

     registerFMRecordingStatus();

 

Activity销毁界面方法

public void onDestroy()

在onDestroy方法里mDelayedStopHandler.removeCallbacksAndMessages(null); 移除回调handler信息

关闭警铃cancelAlarms()

将声音设为音乐焦点
 //release the audio focus listener
      AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
      if (isMuted()) {
          mMuted = false;
          audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false);
      }
      audioManager.abandonAudioFocus(mAudioFocusListener);

遗弃音频管理监听

audioManager.abandonAudioFocus(mAudioFocusListener);

 

在onDestroy方法里卸载注册

    /* Remove the Screen On/off listener */
          if (mScreenOnOffReceiver != null) {
              unregisterReceiver(mScreenOnOffReceiver);
              mScreenOnOffReceiver = null;
          }
          /* Unregister the headset Broadcase receiver */
          
           if (mAirplaneModeReceiver != null) {
              unregisterReceiver(mAirplaneModeReceiver);
              mAirplaneModeReceiver = null;
          }
          
          if (mHeadsetReceiver != null) {unregisterReceiver(mHeadsetReceiver);
              mHeadsetReceiver = null;
          }
          if( mMusicCommandListener != null ) {
              unregisterReceiver(mMusicCommandListener);
              mMusicCommandListener = null;
          }
          if( mFmMediaButtonListener != null ) {
              unregisterReceiver(mFmMediaButtonListener);
              mFmMediaButtonListener = null;
          } if (mAudioBecomeNoisyListener != null) {
              unregisterReceiver(mAudioBecomeNoisyListener);
              mAudioBecomeNoisyListener = null;
          }
          if (mSleepExpiredListener != null ) {
              unregisterReceiver(mSleepExpiredListener);
              mSleepExpiredListener = null;
          }
          if (mRecordTimeoutListener != null) {
              unregisterReceiver(mRecordTimeoutListener);
              mRecordTimeoutListener = null;
          } if (mDelayedServiceStopListener != null) {
              unregisterReceiver(mDelayedServiceStopListener);
              mDelayedServiceStopListener = null;
          }
          if (mFmRecordingStatus != null ) {
              unregisterReceiver(mFmRecordingStatus);
              mFmRecordingStatus = null;
          }


关闭收音机fmOff();关掉调频:禁用调频主机和硬件。

    TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
          tmgr.listen(mPhoneStateListener, 0);
     
          Log.d(LOGTAG, "onDestroy: unbindFromService completed");
     
          //unregisterReceiver(mIntentReceiver);
          mWakeLock.release();


 

mWakeLock.release();//释放唤醒锁

在onDestroy方法里设置电话监听参数0失去监听来电状态

      tmgr.listen(mPhoneStateListener, 0);


public void registerFMRecordingStatus()控制

private void stop() 卸载FMMediaButtonIntentReceiver类的注册

mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

         ComponentName fmRadio = new ComponentName(this.getPackageName(),

                                 FMMediaButtonIntentReceiver.class.getName());

         mAudioManager.unregisterMediaButtonEventReceiver(fmRadio);

stop()方法调用gotoIdleState()方法删除mDelayedStopHandler空消息,关闭警铃

    private void gotoIdleState()
     
    mDelayedStopHandler.removeCallbacksAndMessages(null);
     
         cancelAlarms();
     
         setAlarmDelayedServiceStop();
     
         stopForeground(true);
     
      

public IBinder onBind(Intent intent)绑定service

mDelayedStopHandler.removeCallbacksAndMessages(null);

     cancelAlarms();关闭,警铃

     mServiceInUse = true; 服务可以使用

     /* Application/UI is attached, so get out of lower power mode */

     setLowPowerMode(false);

 

public void onRebind(Intent intent)重新捆绑service

 

public void onStart(Intent intent, intstartId) StartService启动方法

 

public boolean onUnbind(Intent intent) 解绑service

 

获得进程名字方法private String getProcessName()

private void sendRecordIntent(int action) 发送录音无序广播在注册录音广播接收方法中

 

private void sendRecordServiceIntent(intaction) 发送录音状态无序广播

 

private void startFM()启动FM方法:

    if(true == mAppShutdown) { // not to sendintent to AudioManager in Shutdown
     
    if (isCallActive()) { // when Call is activenever let audio playback
     
    if ( true == mPlaybackInProgress ) // no needto resend event


 

请求音频声音焦点

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

 

    /**

     *请求改变焦点失败

     */

    public static final int AUDIOFOCUS_REQUEST_FAILED = 0;

    /**

     *请求改变焦点成功     */

    public static final intAUDIOFOCUS_REQUEST_GRANTED = 1;

 

实现audioManager类的焦点监听接口

     private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
           public void onAudioFocusChange(int focusChange) {
               mDelayedStopHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
           }
       };

 

 

请求声音焦点当music响起fm短时间暂停,music关闭后fm继续播放private void requestFocus()

 

mAudioManager.registerMediaButtonEventReceiver(fmRadio);注册多媒体按钮事件监听

mStoppedOnFocusLoss = false;停止声音焦值为false

停止fm使用

    private void stopFM(){
     
    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,AudioSystem.DEVICE_STATE_UNAVAILABLE,"");
     
    }

重新设置fm

    private void resetFM() {
     
           AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
     
       AudioSystem.DEVICE_STATE_UNAVAILABLE, "")
     
    }

mA2dpDeviceState.isDeviceAvailable()蓝牙耳机设备可用是否可用

mOverA2DP全局变量是用来表示蓝牙是否可用

 

public boolean mute()静音模式 mMute 全局变量作为是否开启静音模式做判断

AudioManager audioManager =(AudioManager) getSystemService(Context.AUDIO_SERVICE);

设置静音audioManager.setStreamMute(AudioManager.STREAM_MUSIC,false);

public booleanisWiredHeadsetAvailable()耳机可用

public boolean isCallActive()通话中,调用getCallState()方法返回0为空闲没有通话,返回1是通话状态。

public void stopRecording()停止录音

private void fmActionOnCallState(int state ) 通话活动状态在进入fm方法privateboolean fmOn()中调用此方法,会用到通话监听获取state值。

public boolean startA2dpPlayback()启动蓝牙播放方法,

 

final Runnable mHeadsetPluginHandler= new Runnable()方法当耳机被拔出就关闭fm

     final Runnable    mHeadsetPluginHandler = new Runnable() {
            public void run() {
                /* Update the UI based on the state change of the headset/antenna*/
                if(!isAntennaAvailable())
                {
                   // if (!isFmOn())
                   //     return;       
                    /* Disable FM and let the UI know */
                    fmOff();
                    try
                    {
                        /* Notify the UI/Activity, only if the service is "bound"
                      by an activity and if Callbacks are registered
                         */
                        if((mServiceInUse) && (mCallbacks != null) )
                        {
                            mCallbacks.onDisabled();
                        }
                    } catch (RemoteException e)
                    {
                        e.printStackTrace();
                    }
                }else
                {
                    /* headset is plugged back in,
                   So turn on FM if:
                   - FM is not already ON.
                   - If the FM UI/Activity is in the foreground
                     (the service is "bound" by an activity
                      and if Callbacks are registered)
                     */
                    if ((!isFmOn()) && (mServiceInUse)
                            && (mCallbacks != null))
                    {
                        if( true != fmOn() ) {
                            return;
                        }
                        try
                        {
                            mCallbacks.onEnabled();
                        } catch (RemoteException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };

public void clearStationInfo()清除fm状态信息

FmRxEvCallbacksAdaptor fmCallbacks= new FmRxEvCallbacksAdaptor() 广播接收类详解

public void FmRxEvEnableReceiver()可用接收

public voidFmRxEvDisableReceiver() 失去接收功能

public void FmRxEvRadioReset()收音机从新设置

调整fm频率并保持

FmSharedPreferences.setTunedFrequency(frequency);

mPrefs.Save();

enableStereo(FmSharedPreferences.getAudioOutputMode());获取立体声音是否可用

更新状态栏的通知信息

startNotification();设计fm在后台播放,service不被杀死,挂一个前台通知,在停止FMRadioService停止前台通知:

startForeground(FMRADIOSERVICE_STATUS,status);

在gotoIdleState()转到fm空闲状态的时候就停止前警铃,后警铃后台服务,前台通知栏等关闭。

mDelayedStopHandler.removeCallbacksAndMessages(null);

      cancelAlarms();

      setAlarmDelayedServiceStop();

      stopForeground(true);

 

readInternalAntennaAvailable() 读的调频的内部天线可用状态

private booleansetAudioPath(boolean analogMode) 安装判断铃声路径

/*
*打开调频:调频硬件启动,并初始化调频模块
* @return返回值为真:如果调频使api调用成功, 假:如果api失败了。
* /

private boolean fmOn()

mReceiver = newFmReceiver(FMRADIO_DEVICE_FD_STRING, fmCallbacks);

从调频堆栈接收回调函数

FmRxEvCallbacksAdaptor fmCallbacks = newFmRxEvCallbacksAdaptor()

 

mReceiver.setRawRdsGrpMask();

FmSharedPreferences.clearTags();清除Tag

Fm重新设置

public void FmRxEvRadioReset()

fmRadioReset();

调整屏幕状态

public void FmRxEvRadioTuneStatus(intfrequency)

FmSharedPreferences.setTunedFrequency(frequency);

           mPrefs.Save();

清除状态信息

if(mReceiver != null) {

    clearStationInfo();

}

更新状态栏通知

startNotification();

判断RDSS支持

public void FmRxEvRdsLockStatus(booleanbRDSSupported)

mCallbacks.onStationRDSSupported(bRDSSupported);

 

更新警铃立体声状态

public void FmRxEvStereoStatus(booleanstereo)

mCallbacks.onAudioUpdate(stereo);

 

public void FmRxEvServiceAvailable(booleansignal)

fm搜索完成

public void FmRxEvSearchComplete(intfrequency)

FmSharedPreferences.setTunedFrequency(frequency);

clearStationInfo();

startNotification();

mWakeLock.acquire(10*1000);唤醒锁屏超时10*1000就释放唤醒对象

电话不是在空闲状态换回false

if ( TelephonyManager.CALL_STATE_IDLE !=getCallState() ) {

        return bStatus;

}

正常进入fm

    if (isFmOn())
     
    {
     
         /* FM Is already on,*/
     
         bStatus = true;
     
         Log.d(LOGTAG, "mReceiver.already enabled");
     
    }

 获取fm配置

FmConfig config =FmSharedPreferences.getFMConfiguration();

 

广播接收获取FM配置状态

bStatus =mReceiver.enable(FmSharedPreferences.getFMConfiguration());

 

扬声器可用设置boolean值

    if (isSpeakerEnabled()) {
     
                    setAudioPath(false);
     
               } else {
     
                    setAudioPath(true);
     
               }

 真正启动fm播放声音是AudioSystem.setDeviceConnectionState(); 设置fm设备启动,设置fm耳机播放还是扬声器播放(核心代码)

    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM,
                                   AudioSystem.DEVICE_STATE_AVAILABLE, "");
               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);
               }


audio焦点监听事件

AudioManager.OnAudioFocusChangeListener是申请成功之后监听AudioFocus使用情况的Listener,后续如果有别的程序要竞争AudioFocus,都是通过这个Listener的onAudioFocusChange()方法来通知这个AudioFocus的使用者的。

请求audio焦点属性

AUDIOFOCUS_GAIN
指示申请得到的AudioFocus不知道会持续多久,一般是长期占有;
AUDIOFOCUS_GAIN_TRANSIENT
指示要申请的AudioFocus是暂时性的,会很快用完释放的;
AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK不但说要申请的AudioFocus是暂时性的,还指示当前正在使用AudioFocus的可以继续播放,只是要“duck”一下(降低音量)。

AUDIOFOCUS_REQUEST_GRANTED:申请成功;
AUDIOFOCUS_REQUEST_FAILED:申请失败。

抢夺焦点
AUDIOFOCUS_GAIN:获得了Audio Focus;
AUDIOFOCUS_LOSS:失去了Audio Focus,并将会持续很长的时间。这里因为可能会停掉很长时间,所以不仅仅要停止Audio的播放,最好直接释放掉Media资源。而因为停止播放Audio的时间会很长,如果程序因为这个原因而失去AudioFocus,最好不要让它再次自动获得AudioFocus而继续播放,不然突然冒出来的声音会让用户感觉莫名其妙,感受很不好。这里直接放弃AudioFocus,当然也不用再侦听远程播放控制【如下面代码的处理】。要再次播放,除非用户再在界面上点击开始播放,才重新初始化Media,进行播放。
AUDIOFOCUS_LOSS_TRANSIENT:暂时失去Audio Focus,并会很快再次获得。必须停止Audio的播放,但是因为可能会很快再次获得AudioFocus,这里可以不释放Media资源;

AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:暂时失去AudioFocus,但是可以继续播放,不过要在降低音量。
 
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flybirding10011

谢谢支持啊999

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值