Audio声音模式定制--声音大小定制

实际场景:

应付客户电子产品的3C认证,声音大小必须小于85DB,但是产品以K歌为特色,外响声音必须大。

解决思路:

设备定义两个声音模式,成人模式和儿童模式。成人模式的音量为原始音量,儿童模式的音量最大值为原始音量最大值得一半,或者更小

解决方案:

  • 自己应用层实现,音量条最大值是自己定义的。
  • 直接系统层Framework层,在Audio层写代码,定制自己的功能。

说明:方案一太LowB,下面具体分析方案二的实现。

需求分析:

  • 模式需要切换,设置儿童模式、是否儿童模式
  • 设置当前儿童模式中Alarm最大音量,获取当前儿童模式最大Alarm音量
  • 设置当前儿童模式Call最大音量,获取当前儿童模式下最大Call音量
  • 设置当前儿童模式Music最大音量,获取当前儿童模式下最大Music音量

特别说明

本文不做Audio层各种流程,各种的原理,只做现有功能逻辑的实现和分析。

IAudioService.aidl 添加接口。

  /**
     * {@hide}
     */
    interface IAudioService {
        void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
                String callingPackage);
        void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage);
        void adjustMasterVolume(int direction, int flags, String callingPackage);
        
    boolean childrenMode();
	void setChildrenMode(boolean ischildren);
    void setAlarmMaxVolumeInChildMode(int index);
	void setCallMaxVolumeInChildMode(int index);
	void setMusicMaxVolumeInChildMode(int index);
	int getAlarmMaxIndexInChildMode();
	int getCallMaxIndexInChildMode();
	int getMusicMaxIndexInChildMode();

    }

AudioService.java 添加具体实现。

第一步:添加默认的声音大小,默认就是儿童模式

 private int mAlarmMaxIndexInChildMode=3;
    private int mMusicMaxIndexInChildMode=6;
    private int mCallMaxIndexInChildMode=2;
    private boolean mIsChildren=true;


可以对比下源码中默认的声音大小
  /** @hide Maximum volume index values for audio streams */
    private static int[] MAX_STREAM_VOLUME = new int[] {
        5,  // STREAM_VOICE_CALL
        7,  // STREAM_SYSTEM
        7,  // STREAM_RING
        15, // STREAM_MUSIC
        7,  // STREAM_ALARM
        7,  // STREAM_NOTIFICATION
        15, // STREAM_BLUETOOTH_SCO
        7,  // STREAM_SYSTEM_ENFORCED
        15, // STREAM_DTMF
        15  // STREAM_TTS
    };

    private static int[] DEFAULT_STREAM_VOLUME = new int[] {
        3,  // STREAM_VOICE_CALL
        4,  // STREAM_VOICE_CALL
        4,  // STREAM_RING
        9, // STREAM_MUSIC
        4,  // STREAM_ALARM
        4,  // STREAM_NOTIFICATION
        9,  // STREAM_BLUETOOTH_SCO
        4,  // STREAM_SYSTEM_ENFORCED
        9, // STREAM_DTMF
        9  // STREAM_TTS
    };

第二步 实现定义的方法

public void setChildrenMode(boolean ischildren){
 mIsChildren=ischildren;
}
public boolean childrenMode(){
	return mIsChildren;
}
public int getAlarmMaxIndexInChildMode(){
	return mAlarmMaxIndexInChildMode;
}
public int getMusicMaxIndexInChildMode(){
	return mMusicMaxIndexInChildMode;
}
public int getCallMaxIndexInChildMode(){
	return mCallMaxIndexInChildMode;
}
public void setAlarmMaxVolumeInChildMode(int index){
 mAlarmMaxIndexInChildMode=index;
}
public void setMusicMaxVolumeInChildMode(int index){
 mMusicMaxIndexInChildMode=index;
}
public void setCallMaxVolumeInChildMode(int index){
 mCallMaxIndexInChildMode=index;
}

第三步,添加应用层和Framework应用层可以设置并获取当前最大音量的方法。

public int getStreamMaxIndex(int streamType){
	int index=-1;
	Log.d("TAG","streamType="+streamType);
	switch(streamType){
		case AudioManager.STREAM_VOICE_CALL:
		index=getCallMaxIndexInChildMode();
		break;
		case AudioManager.STREAM_ALARM:
		index=getAlarmMaxIndexInChildMode();
		break;
		case AudioManager.STREAM_MUSIC:
		index=getMusicMaxIndexInChildMode();
		break;
		default:
		index=3;
		break;
	}
	Log.d("TAG","index="+index);
	return index;
}

public void resetMaxVolume(){
		Log.d("TAG","resetMaxVolume");
		Log.d("TAG","mStreamType="+mStreamType);
		mIndexMax = MAX_STREAM_VOLUME[mStreamType];
		Log.d("TAG","mIndexMax="+mIndexMax);
        AudioSystem.initStreamVolume(mStreamType, 0, mIndexMax);
        mIndexMax *= 10;
        readSettings();
    }

接下来看下控制器Audiomanager的控制逻辑
逻辑控制的常规操作,入口在AudioManager控制类中,实际是通过aidl调用AudioService的

第四步,控制逻辑实现

    /**
     * AudioManager provides access to volume and ringer mode control.
     * <p>
     * Use <code>Context.getSystemService(Context.AUDIO_SERVICE)</code> to get
     * an instance of this class.
     */
获取当前最大音量值
public int getStreamMaxIndex(int streamType){
		int index=-1;
		Log.d("TAG","streamType="+streamType);
		switch(streamType){
			case STREAM_VOICE_CALL:
			index=getCallMaxIndexInChildMode();
			break;
			case STREAM_ALARM:
			index=getAlarmMaxIndexInChildMode();
			break;
			case STREAM_MUSIC:
			index=getMusicMaxIndexInChildMode();
			break;
			default:
			index=3;
			break;
		}
		Log.d("TAG","index="+index);
		return index;
	}
    是否是儿童模式
    public boolean childrenMode(){
		boolean result=false;
		 IAudioService service = getService();
        try {
			result=service.childrenMode();
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in adjustVolume", e);
        }
      return result;
    }

/**
 *设置是否是儿童模式
 *
 */
public void setChildrenMode(boolean ischildren){
 IAudioService service = getService();
    try {
        service.setChildrenMode(ischildren);
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call setChildrenMode(boolean ischildren) on AudioService:", e);
    }
}

/**
 *获取儿童模式下闹铃的最大音量
 */
public int getAlarmMaxIndexInChildMode(){
	int result=-1;
	IAudioService service = getService();
    try {
        result=service.getAlarmMaxIndexInChildMode();
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call setMaxIndexInChildrenMode(int maxIndex) on AudioService:", e);
    }
 return result;
}
/**
 *获取儿童模式下打电话的最大音量
 */
public int getCallMaxIndexInChildMode(){
	int result=-1;
	IAudioService service = getService();
    try {
        result=service.getCallMaxIndexInChildMode();
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call setMaxIndexInChildrenMode(int maxIndex) on AudioService:", e);
    }
 return result;
}
public int getMusicMaxIndexInChildMode(){
	int result=-1;
	IAudioService service = getService();
    try {
        result=service.getMusicMaxIndexInChildMode();
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call getMusicMaxIndexInChildMode(int index) on AudioService:", e);
    }
 return result;
}
public void setAlarmMaxVolumeInChildMode(int index){
 IAudioService service = getService();
    try {
        service.setAlarmMaxVolumeInChildMode(index);
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call setAlarmMaxVolumeInChildMode(int index) on AudioService:", e);
    }
}
public void setMusicMaxVolumeInChildMode(int index){ 
IAudioService service = getService();
    try {
        service.setMusicMaxVolumeInChildMode(index);
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call setMusicMaxVolumeInChildMode(int index) on AudioService:", e);
    }
}
public void setCallMaxVolumeInChildMode(int index){
 IAudioService service = getService();
    try {
		service.setCallMaxVolumeInChildMode(index);
    } catch (RemoteException e) {
        Log.e(TAG, "Can't call setCallMaxVolumeInChildMode(int index) on AudioService:", e);
    }
}

基于以上已经完成了Audio层的接口扩展,现在怎么应用呢?
对于自带的系统进度条,

  • 首先看是否是儿童模式,
  • 获取最大的音量值给系统音量条【进度条】作为最大值
    那么就需要更改VolumePanel.java了。
  private int getStreamMaxVolume(int streamType) {
            if (streamType == STREAM_MASTER) {
                return mAudioManager.getMasterMaxVolume();
            } else if (streamType == STREAM_REMOTE_MUSIC) {
                if (mStreamControls != null) {
                    StreamControl sc = mStreamControls.get(streamType);
                    if (sc != null && sc.controller != null) {
                        PlaybackInfo ai = sc.controller.getPlaybackInfo();
                        return ai.getMaxVolume();
                    }
                }
                return -1;
            } else {
    		 	if(mAudioManager.childrenMode()){                                //判断一次,如果是儿童模式就直接获取自己定义的值就可以了
    				return mAudioManager.getStreamMaxIndex(streamType);
    			}else{
    				return mAudioManager.getStreamMaxVolume(streamType);
    			}
            }
        }

以上也是整个系统层的设置,逻辑功能实现,页面展现实现。那么实际切换应该放在应用层实现。

代码如下:
每次进入app默认设置一下音频大小、模式。对于Launcher定制案子,每次进入Launcher也就是开机后就初始化一下状态
调用方法 setMusicMaxVolumeInChildMode setCallMaxVolumeInChildMode

 private void initVolume() {
        LauncherApp.getInstance().getAsrAsynHandler().postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    setChildrenMode(PreferencesUtils.getBoolean(LauncherApp.getInstance(),PreferencesUtils.mIsChildMode,true));
                }catch (Exception e){

                }
                AudioManager audioManager= (AudioManager) getSystemService(AUDIO_SERVICE);
                try {
                    Method method=audioManager.getClass().getDeclaredMethod("setMusicMaxVolumeInChildMode",int.class);
                    method.setAccessible(true);
                    method.invoke(audioManager,ConfigConst.mMusicMaxVolumeChildrenMode);
                }catch (Exception e){
                    e.printStackTrace();
                }
                try {
                    Method method=audioManager.getClass().getDeclaredMethod("setCallMaxVolumeInChildMode",int.class);
                    method.setAccessible(true);
                    method.invoke(audioManager,ConfigConst.mCallMaxVolumeChildrenMode);
                }catch (Exception e){
                    e.printStackTrace();
                }
                if (audioManager == null) {
                    return;
                }
                audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                        audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) , AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
            }
        },2000);
    }

如果需要重置恢复到正常的音频模式,声音大小:
调用方法: setChildrenMode(true); resetChildVolume();

  public void setChildrenMode(boolean child){
        LogUtils.d("EgMainActivity  setChildrenMode:"+child);
        AudioManager audioManager= (AudioManager) getSystemService(AUDIO_SERVICE);
        try {
            Method method=audioManager.getClass().getDeclaredMethod("setChildrenMode",boolean.class);
            method.setAccessible(true);
            method.invoke(audioManager,child);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void resetChildVolume(){
        AudioManager audioManager= (AudioManager) getSystemService(AUDIO_SERVICE);
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                ConfigConst.mMusicMaxVolumeChildrenMode,
                AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
        audioManager.setStreamVolume(AudioManager.STREAM_ALARM,
                ConfigConst.mAlarmMaxVolumeChildrenMode,
                AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                ConfigConst.mCallMaxVolumeChildrenMode,
                AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
    }

如果切换到儿童模式:
调用方法 setChildrenMode(true); resetChildVolume();

public void setChildrenMode(boolean child){
        AudioManager audioManager= (AudioManager) getSystemService(AUDIO_SERVICE);
        try {
            Method method=audioManager.getClass().getDeclaredMethod("setChildrenMode",boolean.class);
            method.setAccessible(true);
            method.invoke(audioManager,child);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void resetChildVolume(){
        AudioManager audioManager= (AudioManager) getSystemService(AUDIO_SERVICE);
        audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                ConfigConst.mMusicMaxVolumeChildrenMode,
                AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
        audioManager.setStreamVolume(AudioManager.STREAM_ALARM,
                ConfigConst.mAlarmMaxVolumeChildrenMode,
                AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
        audioManager.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                ConfigConst.mCallMaxVolumeChildrenMode,
                AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
    }

源码下载地址

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值