文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android中如何进行绝对音量和相对音量设置

2023-06-28 23:56

关注

这篇文章给大家介绍Android中如何进行绝对音量和相对音量设置,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

前言:

绝对音量: 手机端不处理音量,只把当前音量告诉耳机,耳机端处理音量。

相对音量: 手机端处理,耳机端不确定是默认最大,还是有一个默认音量还是按照之前设置的绝对音量的值处理的。

手机音量转换绝对音量,此处会有一个计算过程,大致就是手机侧计算出当前音量和最大音量的百分比然后设置给耳机,耳机端收到百分比去处理。不然每个手机的音量范围不同,不做归一化就很难适配。

当通过音量按键调节音量时,会通过input事件分发,input把event分发给mediassesion, mediasession调用audiomanager的adjustStreamVolume调节音量。

当通过拖动音量条调节音量时,settings app会调用audiomanager的setStreamVolume调节音量。

adjustStreamVolume和setStreamVolume处理过程类似,接下来只看setStreamVolume。

setStreamVolume调用

// frameworks/base/media/java/android/media/AudioManager.javapublic void setStreamVolume(int streamType, int index, int flags) {    final IAudioService service = getService();    try {        service.setStreamVolume(streamType, index, flags, getContext().getOpPackageName()); // audiomanager调用的是audioservice的setStreamVolume    } catch (RemoteException e) {        throw e.rethrowFromSystemServer();    }}

audioservice的调用过程:

// frameworks/base/services/core/java/com/android/server/audio/AudioService.javaprivate void setStreamVolume(int streamType, int index, int flags, String callingPackage, String caller, int uid, boolean hasModifyAudioSettings) {    ensureValidStreamType(streamType);    int streamTypeAlias = mStreamVolumeAlias[streamType];    VolumeStreamState streamState = mStreamStates[streamTypeAlias];    inal int device = getDeviceForStream(streamType); // 获取streamType对应的device    int oldIndex;      synchronized (mSafeMediaVolumeStateLock) {        // reset any pending volume command        mPendingVolumeCommand = null;        oldIndex = streamState.getIndex(device);        android.media.AudioServiceInjector.mOriginalIndexWhenSetStreamVolume = index;        index = rescaleIndex(index * 10, streamType, streamTypeAlias);         // 设置绝对音量        if (streamTypeAlias == AudioSystem.STREAM_MUSIC && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {            mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);        }         if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {            setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags); // 这里是和hdmi相关,不用管        }         flags &= ~AudioManager.FLAG_FIXED_VOLUME;        if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {            flags |= AudioManager.FLAG_FIXED_VOLUME;             // volume is either 0 or max allowed for fixed volume devices            if (index != 0) {                if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && mSafeMediaVolumeDevices.contains(device)) {                   index = safeMediaVolumeIndex(device);                } else {                   index = streamState.getMaxIndex();                }            }        }         if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {            mVolumeController.postDisplaySafeVolumeWarning(flags); // 这里应该就是安全提醒,比如音量过大损伤听力的提醒            mPendingVolumeCommand = new StreamVolumeCommand(streamType, index, flags, device);        } else {            onSetStreamVolume(streamType, index, flags, device, caller, hasModifyAudioSettings); // 调用onSetStreamVolume设置音量            index = mStreamStates[streamType].getIndex(device);        }    }    sendVolumeUpdate(streamType, oldIndex, index, flags, device); }

onSetStreamVolume 和 sendVolumeUpdate的作用:

onSetStreamVolume -> 设置音量到底层并处理一些静音逻辑。

sendVolumeUpdate -> 通知ui更新音量值

这里插入个当音量设置到0时自动静音的处理:

// frameworks/base/services/core/java/com/android/server/audio/AudioService.javaprivate void onSetStreamVolume(int streamType, int index, int flags, int device, String caller, boolean hasModifyAudioSettings) {    final int stream = mStreamVolumeAlias[streamType];    setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings); // 设置音量到底层    // setting volume on ui sounds stream type also controls silent mode    if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (stream == getUiSoundsStreamType())) {       int ringerMode = getNewRingerMode(stream, index, flags); // 获取ringmode        miuiRingerMode = miui.util.AudioManagerHelper.getValidatedRingerMode(mContext, miuiRingerMode); // 获取ringmode        setRingerMode(ringerMode, TAG + ".onSetStreamVolume", false ); // 设置ringmode    }}    private int getNewRingerMode(int stream, int index, int flags) {    if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (stream == getUiSoundsStreamType())) {        int newRingerMode;        if (index == 0) { // 如果设置的音量是0        // 如果有震动就设置ringmode是震动模式,否则判断volumeDownToEnterSilent决定设置静音还是不静音            newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT : AudioManager.RINGER_MODE_NORMAL;        } else {            newRingerMode = AudioManager.RINGER_MODE_NORMAL; // 如果音量不是0,ringmode设置为非静音        }        return newRingerMode;    }    return getRingerModeExternal();}

设置绝对音量: postSetAvrcpAbsoluteVolumeIndex

// frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.javavoid postSetAvrcpAbsoluteVolumeIndex(int index) {    sendIMsgNoDelay(MSG_I_SET_AVRCP_ABSOLUTE_VOLUME, SENDMSG_REPLACE, index);} // 收到消息MSG_I_SET_AVRCP_ABSOLUTE_VOLUME,调用mBtHelper.setAvrcpAbsoluteVolumeIndex(msg.arg1); // frameworks/base/services/core/java/com/android/server/audio/BtHelper.javasynchronized void setAvrcpAbsoluteVolumeIndex(int index) {    mA2dp.setAvrcpAbsoluteVolume(index);}

蓝牙侧绝对音量处理:

// vendor/qcom/opensource/commonsys/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpService.javapublic void setAvrcpAbsoluteVolume(int volume) {    if (mFactory.getAvrcpTargetService() != null) {        mFactory.getAvrcpTargetService().sendVolumeChanged(volume);        return;    }    if(ApmConstIntf.getLeAudioEnabled()) {        VolumeManagerIntf mVolumeManager = VolumeManagerIntf.get();        mVolumeManager.setMediaAbsoluteVolume(volume);        return;    }    synchronized(mBtAvrcpLock) {        if (mAvrcp_ext != null) {           mAvrcp_ext.setAbsoluteVolume(volume);           return;        }        if (mAvrcp != null) {           mAvrcp.setAbsoluteVolume(volume);        }    }} // vendor/qcom/opensource/commonsys/bluetooth_ext/packages_apps_bluetooth_ext/src/avrcp/Avrcp_ext.javapublic void setAbsoluteVolume(int volume) {    Message msg = mHandler.obtainMessage(MSG_SET_ABSOLUTE_VOLUME, volume, 0);    mHandler.sendMessage(msg);} 收到消息MSG_SET_ABSOLUTE_VOLUME之后调用如下case MSG_SET_ABSOLUTE_VOLUME: {    int avrcpVolume = convertToAvrcpVolume(msg.arg1);    ......} // 计算avrcpVolumeprivate int convertToAvrcpVolume(int volume) {   if(mAudioStreamMax == 150) {       return (int) Math.round((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);   }   return (int) Math.ceil((double) volume*AVRCP_MAX_VOL/mAudioStreamMax);}

从这里可以看到,蓝牙侧传给耳机的音量其实就是百分比。

从相对音量切换到绝对音量的处理:

蓝牙APP有一个NotificationReceiver,当绝对音量的开关发生变化NotificationReceiver就会收到信息,然后做如下处理:

private class NotificationReceiver extends BroadcastReceiver {    public void onReceive(Context context, Intent intent) {        if(ABS_VOLUME_ACTION.equals(intent.getAction())) {            handleDeviceAbsVolume(mac, value);        }    }}// handleDeviceAbsVolume就会做对应的处理,把音量值发送给耳机侧。

此处每次切换的时候会有log打印,log mask: handleDeviceAbsVolume|setVolumeNative

切换之后播放声音就会调用checkAndSetVolume把音量值设置到最大,保证手机侧无音量处理。

从绝对音量切换到相对音量的处理:

和上面一样,蓝牙APP NotificationReceiver会收到绝对音量开关关闭的消息,然后把消息发给耳机端。然后还会调用audio侧设置stream的音量。

log mask: handleDeviceAbsVolume|setStreamVolume

切换之后播放声音就会调用checkAndSetVolume把音量值设置到当前实际的音量值。

Android是什么

Android是一种基于Linux内核的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑,由美国Google公司和开放手机联盟领导及开发。

关于Android中如何进行绝对音量和相对音量设置就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯