机制和策略相分离原则

这些天大刀阔斧修改了我们的alsa音频驱动,更深切理解了机制和策略分离的重要性。

说来惭愧,Linux Device Drivers一书翻来覆去查阅了无数遍,却忽视了绪论中的一句话:区分机制和策略是Unix设计背后隐含的最好思想之一。

“需要提供什么功能”即机制,“如何使用这些功能”即策略。一年多前,初接手音频驱动开发时,就混淆了机制和策略,主要表现在音频通道方面。

最典型的例如:当codec检测到有headset插入时,就关闭speaker,声音转向headset输出;而检测到headset拔下时,关闭headset通道,声音转向speaker输出。

这个做法,我当时就认为是正确的场景。可是却没有考虑到一些特殊的场景:如在headset插入的状态下,这时如果是闹钟铃声或电话铃声的话,声音还是必须要speaker出来的。

各种应用场景千奇百怪,作为底层的不能假设什么策略是正确的,更不应该擅自去实现这些策略。只需要提供相关的功能即可,上层根据需要来调用这些接口。

还是以上述的音频通道为例:

1、在codec驱动中会实现snd_kcontrol(mixer control)、dapm、audio_map等,如

SOC_SINGLE("Headset Switch", xxx_HEADSET_REG, 0, 1, 0),
SOC_SINGLE("Headfree Switch", xxx_HEADFREE_REG, 0, 1, 0),
上面两个mixer control可对headset和headfree这两个通道进行切换控制。

2、当Android系统跑起来后,可用tinymix命令(Android4.0版本,如果是之前版本的话,用alsa_amixer命令)可看到:

17      BOOL    1       Headset Switch                           Off
18      BOOL    1       Headfree Switch                          Off
因为目前没有声音需要输出,因此这两个通道都是关闭的。

3、在Android的音频抽象层audio_hw.c可这样定义:

struct route_setting hf_output[] = {
    {
        .ctl_name = "Headfree Switch",
        .intval = 1,
    },

    /* end of the route_setting */
    {
        .ctl_name = NULL,
    },
};

struct route_setting hs_output[] = {
    {
        .ctl_name = "Headset Switch",
        .intval = 1,
    },

    /* end of the route_setting */
    {
        .ctl_name = NULL,
    },    
};
这样程序可以根据AudioPolicyService提供的音频策略来控制底层的音频通路:

    headset_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
    headphone_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
    speaker_on = adev->devices & AUDIO_DEVICE_OUT_SPEAKER;
    earpiece_on = adev->devices & AUDIO_DEVICE_OUT_EARPIECE;
    bt_on = adev->devices & AUDIO_DEVICE_OUT_ALL_SCO;

    /* select output stage */
    set_route_by_array(adev->mixer, hs_output, headset_on | headphone_on);
    set_route_by_array(adev->mixer, hf_output, speaker_on);

你可能感兴趣的:(机制和策略相分离原则)