3. ALSA参数配置与查询

任务目标

编写一个ALSA用户空间程序,完成以下功能:

  1. 打开默认PCM设备(default);
  2. 查询当前采样率、通道数、格式等硬件参数;
  3. 设置目标参数:采样率44100Hz、双通道、S16_LE格式;
  4. 再次查询并打印设置后的实际参数,验证配置是否生效。

环境与依赖

  • Linux系统,内核已启用ALSA驱动;
  • 安装ALSA用户态开发库:sudo apt-get install libasound2-dev(Debian/Ubuntu);
  • 编译时链接 -lasound。

关键完整代码

#include <stdio.h>
#include <alsa/asoundlib.h>

static void print_hw_params(snd_pcm_t *handle) {
    snd_pcm_hw_params_t *hw;
    snd_pcm_hw_params_alloca(&hw);

    if (snd_pcm_hw_params_current(handle, hw) < 0) {
        printf("获取当前硬件参数失败\n");
        return;
    }

    unsigned int rate;
    int dir;
    snd_pcm_uframes_t period_size, buffer_size;
    snd_pcm_format_t format;
    unsigned int channels;

    snd_pcm_hw_params_get_rate(hw, &rate, &dir);
    snd_pcm_hw_params_get_format(hw, &format);
    snd_pcm_hw_params_get_channels(hw, &channels);
    snd_pcm_hw_params_get_period_size(hw, &period_size, &dir);
    snd_pcm_hw_params_get_buffer_size(hw, &buffer_size);

    printf("采样率: %u Hz\n", rate);
    printf("通道数: %u\n", channels);
    printf("格式: %s\n", snd_pcm_format_name(format));
    printf("周期大小: %lu 帧\n", (unsigned long)period_size);
    printf("缓冲区大小: %lu 帧\n", (unsigned long)buffer_size);
}

int main() {
    snd_pcm_t *handle;
    int rc;

    // 1. 打开PCM设备(播放方向)
    rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if (rc < 0) {
        fprintf(stderr, "无法打开PCM设备: %s\n", snd_strerror(rc));
        return 1;
    }

    printf("=== 设置前硬件参数 ===\n");
    print_hw_params(handle);

    // 2. 设置硬件参数
    snd_pcm_hw_params_t *hw;
    snd_pcm_hw_params_alloca(&hw);
    snd_pcm_hw_params_any(handle, hw);

    // 设置访问模式为交错模式
    snd_pcm_hw_params_set_access(handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED);

    // 设置格式为S16_LE
    snd_pcm_hw_params_set_format(handle, hw, SND_PCM_FORMAT_S16_LE);

    // 设置采样率44100Hz(允许驱动微调)
    unsigned int rate = 44100;
    int dir = 0;
    snd_pcm_hw_params_set_rate_near(handle, hw, &rate, &dir);

    // 设置通道数为2
    snd_pcm_hw_params_set_channels(handle, hw, 2);

    // 将配置写入驱动
    rc = snd_pcm_hw_params(handle, hw);
    if (rc < 0) {
        fprintf(stderr, "设置硬件参数失败: %s\n", snd_strerror(rc));
        snd_pcm_close(handle);
        return 1;
    }

    printf("\n=== 设置后硬件参数 ===\n");
    print_hw_params(handle);

    // 3. 验证设置结果
    unsigned int actual_rate;
    snd_pcm_hw_params_current(handle, hw);
    snd_pcm_hw_params_get_rate(hw, &actual_rate, &dir);
    printf("\n请求采样率: 44100 Hz, 实际采样率: %u Hz\n", actual_rate);

    if (actual_rate == 44100) {
        printf("参数设置成功\n");
    } else {
        printf("注意: 驱动返回的采样率为 %u Hz(设备可能不支持44100Hz)\n", actual_rate);
    }

    snd_pcm_close(handle);
    return 0;
}

编译与运行

gcc -o alsa_param alsa_param.c -lasound
./alsa_param

验证方法与判定标准

  1. 编译通过:无错误,生成可执行文件 alsa_param;
  2. 运行输出:程序依次打印设置前、设置后的硬件参数;
  3. 判定通过条件:设置后的输出中,采样率为44100Hz(或驱动返回的最近值)、通道数为2、格式为S16_LE;若设备不支持44100Hz,程序会打印实际采样率并提示,此时仍属正常行为——只要设置后的参数与驱动实际能力一致即可判定程序功能正确。

常见问题

  • 打开设备失败:确认声卡驱动已加载,且当前用户有权限访问/dev/snd/*;可尝试sudo ./alsa_param。
  • 设置采样率失败:部分USB声卡或板载声卡不支持44100Hz,改用snd_pcm_hw_params_set_rate_near后驱动会返回最接近的可用值,程序会打印实际值。
  • 格式名称显示为Unknown:说明驱动返回了非标准格式,可检查声卡实际能力(cat /proc/asound/card0/pcm0p/sub0/hw_params)。