4. 案例4

任务说明

本案例提供一个存在路由选择错误的音频通路管理模块。该模块根据当前音频策略(如通话、媒体、铃声)选择输出设备,但代码中路由判断逻辑存在缺陷,导致音频始终流向默认设备。你的任务是定位错误的路由选择逻辑,修正后使音频能根据策略正确路由到对应设备(扬声器或耳机)。

问题代码

// audio_router.c
#include <stdbool.h>
#include <string.h>

typedef enum {
    DEVICE_SPEAKER = 0,
    DEVICE_HEADSET = 1,
    DEVICE_BLUETOOTH = 2
} audio_device_t;

typedef enum {
    POLICY_MEDIA = 0,
    POLICY_CALL = 1,
    POLICY_RING = 2
} audio_policy_t;

typedef struct {
    audio_policy_t policy;
    bool headset_connected;
    bool bluetooth_connected;
} audio_state_t;

// 当前路由选择函数(存在逻辑错误)
audio_device_t select_route(audio_state_t *state) {
    audio_device_t device = DEVICE_SPEAKER;

    // 错误点1:条件判断使用赋值而非相等比较
    if (state->policy = POLICY_CALL) {
        // 错误点2:通话策略下未优先检查蓝牙
        if (state->headset_connected) {
            device = DEVICE_HEADSET;
        }
    } else if (state->policy == POLICY_RING) {
        // 错误点3:铃声策略下错误地优先选择扬声器
        device = DEVICE_SPEAKER;
        if (state->headset_connected) {
            device = DEVICE_HEADSET;
        }
    } else {
        // 媒体策略
        if (state->bluetooth_connected) {
            device = DEVICE_BLUETOOTH;
        } else if (state->headset_connected) {
            device = DEVICE_HEADSET;
        }
    }
    return device;
}

路由规则要求

  • 通话策略:优先蓝牙 → 其次耳机 → 最后扬声器
  • 铃声策略:优先耳机 → 其次扬声器(不使用蓝牙)
  • 媒体策略:优先蓝牙 → 其次耳机 → 最后扬声器

修正后的代码

// audio_router_fixed.c
#include <stdbool.h>
#include <string.h>

typedef enum {
    DEVICE_SPEAKER = 0,
    DEVICE_HEADSET = 1,
    DEVICE_BLUETOOTH = 2
} audio_device_t;

typedef enum {
    POLICY_MEDIA = 0,
    POLICY_CALL = 1,
    POLICY_RING = 2
} audio_policy_t;

typedef struct {
    audio_policy_t policy;
    bool headset_connected;
    bool bluetooth_connected;
} audio_state_t;

// 修正后的路由选择函数
audio_device_t select_route(audio_state_t *state) {
    audio_device_t device = DEVICE_SPEAKER;

    if (state->policy == POLICY_CALL) {
        // 通话:蓝牙优先
        if (state->bluetooth_connected) {
            device = DEVICE_BLUETOOTH;
        } else if (state->headset_connected) {
            device = DEVICE_HEADSET;
        } else {
            device = DEVICE_SPEAKER;
        }
    } else if (state->policy == POLICY_RING) {
        // 铃声:耳机优先,不使用蓝牙
        if (state->headset_connected) {
            device = DEVICE_HEADSET;
        } else {
            device = DEVICE_SPEAKER;
        }
    } else {
        // 媒体:蓝牙优先
        if (state->bluetooth_connected) {
            device = DEVICE_BLUETOOTH;
        } else if (state->headset_connected) {
            device = DEVICE_HEADSET;
        } else {
            device = DEVICE_SPEAKER;
        }
    }
    return device;
}

验证方法

编写以下测试用例并编译运行,确认输出与预期一致:

// test_router.c
#include <stdio.h>
#include <assert.h>

// 此处粘贴修正后的 select_route 及类型定义

int main() {
    audio_state_t st;

    // 测试1:通话 + 蓝牙已连接 → 应选蓝牙
    st.policy = POLICY_CALL;
    st.headset_connected = false;
    st.bluetooth_connected = true;
    assert(select_route(&st) == DEVICE_BLUETOOTH);

    // 测试2:通话 + 仅耳机 → 应选耳机
    st.policy = POLICY_CALL;
    st.headset_connected = true;
    st.bluetooth_connected = false;
    assert(select_route(&st) == DEVICE_HEADSET);

    // 测试3:通话 + 无外设 → 应选扬声器
    st.policy = POLICY_CALL;
    st.headset_connected = false;
    st.bluetooth_connected = false;
    assert(select_route(&st) == DEVICE_SPEAKER);

    // 测试4:铃声 + 耳机已连接 → 应选耳机(即使蓝牙也连接)
    st.policy = POLICY_RING;
    st.headset_connected = true;
    st.bluetooth_connected = true;
    assert(select_route(&st) == DEVICE_HEADSET);

    // 测试5:铃声 + 无耳机 → 应选扬声器
    st.policy = POLICY_RING;
    st.headset_connected = false;
    st.bluetooth_connected = true;
    assert(select_route(&st) == DEVICE_SPEAKER);

    // 测试6:媒体 + 蓝牙已连接 → 应选蓝牙
    st.policy = POLICY_MEDIA;
    st.headset_connected = true;
    st.bluetooth_connected = true;
    assert(select_route(&st) == DEVICE_BLUETOOTH);

    // 测试7:媒体 + 仅耳机 → 应选耳机
    st.policy = POLICY_MEDIA;
    st.headset_connected = true;
    st.bluetooth_connected = false;
    assert(select_route(&st) == DEVICE_HEADSET);

    printf("全部测试通过:路由选择逻辑正确\n");
    return 0;
}

编译与运行

gcc -o test_router test_router.c -Wall
./test_router

程序输出 全部测试通过:路由选择逻辑正确 即表示修正成功。若断言失败,程序会中止并提示对应行号。

错误根因总结

  • 赋值代替比较:if (state->policy = POLICY_CALL) 将常量赋给变量,表达式值恒为真,导致所有策略都进入通话分支。
  • 优先级缺失:通话分支未检查蓝牙连接状态,导致蓝牙设备无法被选中。
  • 铃声策略错误:铃声分支先设扬声器再判断耳机,逻辑上虽能工作但顺序混乱;且未明确排除蓝牙,实际因赋值错误从未进入此分支。