Android Audio 广播之 ACTION_AUDIO_BECOMING_NOISY

一、判断广播是否发出

  1. checkSendBecomingNoisyIntentInt

用于判断在音频设备状态改变时(特别是断开连接时),是否需要向媒体应用发送 ACTION_AUDIO_BECOMING_NOISY广播。

主要职责是评估断开连接的设备是否是当前活跃的音频输出设备,以及当前系统状态(是否有音乐播放、是否处于通话中等),

并最终决定是否需要发送广播,如果需要,则返回一个延迟时间(通常用于等待蓝牙设备的短暂重连机会)。

java 复制代码
// 创建一个 MediaMetrics 对象用于记录该方法的执行指标。
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
        + "checkSendBecomingNoisyIntentInt")
        // 设置属性:正在评估的设备名称。
        .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(device))
        // 设置属性:设备的连接状态(已连接或已断开)。
        .set(MediaMetrics.Property.STATE,
                state == AudioService.CONNECTION_STATE_CONNECTED
                        ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED);

// 情况1:如果设备状态不是"断开连接",则无需发送广播,直接返回。
if (state != AudioService.CONNECTION_STATE_DISCONNECTED) {
    Log.i(TAG, "not sending NOISY: state=" + state);
    mmi.set(MediaMetrics.Property.DELAY_MS, 0).record(); // 记录延迟时间为0,然后返回。
    return 0;
}

// 情况2:如果断开连接的设备类型不在预设的"需要发送NOISY广播的设备集合"中,也无需发送,直接返回。
if (!BECOMING_NOISY_INTENT_DEVICES_SET.contains(device)) {
    Log.i(TAG, "not sending NOISY: device=0x" + Integer.toHexString(device)
            + " not in set " + BECOMING_NOISY_INTENT_DEVICES_SET);
    mmi.set(MediaMetrics.Property.DELAY_MS, 0).record();
    return 0;
}

// 延迟时间变量,默认0。
int delay = 0;
// 创建一个集合,用于存储当前所有已连接且应触发NOISY广播的**输出设备**类型。
Set<Integer> devices = new HashSet<>();
// 遍历所有已连接的设备。
for (DeviceInfo di : mConnectedDevices.values()) {
    // 筛选条件:1. 是输出设备;2. 设备类型在上述集合中。
    if (!AudioSystem.isInputDevice(di.mDeviceType)
            && BECOMING_NOISY_INTENT_DEVICES_SET.contains(di.mDeviceType)) {
        // 满足条件的设备类型加入集合。
        devices.add(di.mDeviceType);
        Log.i(TAG, "NOISY: adding 0x" + Integer.toHexString(di.mDeviceType));
    }
}

// 如果传入的 `musicDevice` 参数表示"未指定",则查询系统当前实际用于音乐播放(STREAM_MUSIC)的设备。
if (musicDevice == AudioSystem.DEVICE_NONE) {
    musicDevice = mDeviceBroker.getDeviceForStream(AudioSystem.STREAM_MUSIC);
    Log.i(TAG, "NOISY: musicDevice changing from NONE to 0x"
            + Integer.toHexString(musicDevice));
}

// **核心逻辑判断**:决定是否发送广播。
// 准备判断所需的状态变量:
// 1. 系统是否正在通信中(例如,通话或语音识别)。
final boolean inCommunication = mDeviceBroker.isInCommunication();
// 2. 判断断开连接的设备是否是集合 `devices` 中唯一或最后一个符合NOISY触发条件的音频设备类型。
final boolean singleAudioDeviceType = AudioSystem.isSingleAudioDeviceType(devices, device);
// 3. 是否有动态音频策略正在影响媒体路由。
final boolean hasMediaDynamicPolicy = mDeviceBroker.hasMediaDynamicPolicy();

// 判断条件全部满足时,才需要发送广播:
// 1. 条件A:断开连接的设备是当前音乐播放设备 **或者** 系统正处于通信模式。
// 2. 条件B:该断开连接的设备是唯一或最后一个应触发NOISY的音频设备类型。
// 3. 条件C:没有动态音频策略影响媒体路由。
// 4. 条件D:当前音乐播放设备不是远程子混音设备(`DEVICE_OUT_REMOTE_SUBMIX`,通常用于屏幕录制或投屏)。
if (((device == musicDevice) || inCommunication)
        && singleAudioDeviceType
        && !hasMediaDynamicPolicy
        && (musicDevice != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)) {
    
    // **进一步检查**:即使满足以上条件,如果系统当前既没有播放音乐,也没有持有音频焦用的用户,则不应视为"即将嘈杂",无需打断远程播放的应用。
    if (!mAudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/)
            && !mDeviceBroker.hasAudioFocusUsers()) {
        AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
                "dropping ACTION_AUDIO_BECOMING_NOISY")).printLog(TAG));
        mmi.set(MediaMetrics.Property.DELAY_MS, 0).record();
        return 0;
    }
    // **发送广播**:所有条件满足,提交一个延迟发送"即将嘈杂"广播的任务。
    mDeviceBroker.postBroadcastBecomingNoisy();
    // 设置返回的延迟时间(通常是预定义的常量,例如 `AudioService.BECOMING_NOISY_DELAY_MS`)。
    delay = AudioService.BECOMING_NOISY_DELAY_MS;
} else {
    // 如果以上条件不满足,则记录详细的日志,说明不发送广播的原因。
    Log.i(TAG, "not sending NOISY: device:0x" + Integer.toHexString(device)
            + " musicDevice:0x" + Integer.toHexString(musicDevice)
            + " inComm:" + inCommunication
            + " mediaPolicy:" + hasMediaDynamicPolicy
            + " singleDevice:" + singleAudioDeviceType);
}

// 最终记录本次调用计算的延迟时间指标,并返回该值。
mmi.set(MediaMetrics.Property.DELAY_MS, delay).record();
return delay;
相关推荐
桂花很香,旭很美1 小时前
大模型项目实战:Python 异步——提速、流式、多 Agent
python·language model
yaoxin5211231 小时前
330. Java Stream API - 处理 Optional 对象:像流一样优雅地使用 Optional
java·windows·python
追随者永远是胜利者1 小时前
(LeetCode-Hot100)301. 删除无效的括号
java·算法·leetcode·职场和发展·go
追随者永远是胜利者2 小时前
(LeetCode-Hot100)239. 滑动窗口最大值
java·算法·leetcode·职场和发展·go
今心上2 小时前
spring中的@Autowired到底是什么
java·后端·spring
ShiJiuD6668889992 小时前
Java 异常 File
java·开发语言
码界筑梦坊2 小时前
332-基于XGBoost与SHAP的可穿戴设备亚健康风险识别系统
python·数据分析·flask·vue·毕业设计
lxl13072 小时前
C++算法(5)位运算
java·c++·算法
啊阿狸不会拉杆2 小时前
《计算机视觉:模型、学习和推理》第 7 章-复杂数据密度建模
人工智能·python·学习·算法·计算机视觉·t分布·复杂数据密度建模