嵌入式音频开发笔记——ALSA-Lib常用音频接口函数

snd_pcm_open 函数概述

snd_pcm_open 是 ALSA(Advanced Linux Sound Architecture)库中用于打开 PCM(Pulse Code Modulation)设备的函数。它允许应用程序与音频硬件或虚拟设备建立连接,为后续的音频流操作(如播放或录制)做准备。

函数原型

int snd_pcm_open(snd_pcm_t **pcm, 
                 const char *name, 
                 snd_pcm_stream_t stream, 
                 int mode);

参数说明

  • pcm:指向 snd_pcm_t 类型指针的指针,用于存储打开的 PCM 设备句柄。
  • name:字符串,指定要打开的 PCM 设备名称(如 "default""hw:0,0" 等)。
  • stream:指定音频流方向,取值为 SND_PCM_STREAM_PLAYBACK(播放)或 SND_PCM_STREAM_CAPTURE(录制)。
  • mode:打开模式,常用值为 0(阻塞模式)或 SND_PCM_NONBLOCK(非阻塞模式)。

返回值

  • 成功时返回 0,失败时返回负的错误代码(如 -ENOENT 表示设备不存在)。

常见设备名称

  • "default":系统默认设备,通常由 ALSA 配置自动选择。
  • "hw:0,0":直接访问硬件设备(卡 0,设备 0)。
  • "plughw:0,0":通过插件层访问硬件设备(支持格式转换等)。

注意事项

  1. 打开设备后需检查返回值,确保操作成功。
  2. 使用完成后需调用 snd_pcm_close 释放资源。
  3. 非阻塞模式下,I/O 操作可能立即返回 -EAGAIN,需结合轮询或事件处理。

错误处理

可以通过 snd_strerror(err) 将错误代码转换为可读字符串,便于调试。

snd_pcm_hw_params_set_access 函数详解

snd_pcm_hw_params_set_access 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于设置 PCM(脉冲编码调制)设备的硬件参数中的访问模式。该函数定义了数据在应用程序和硬件之间的传输方式。

函数原型

int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, 
                                 snd_pcm_hw_params_t *params, 
                                 snd_pcm_access_t access);

参数说明

  • pcm: PCM 设备的句柄,通常由 snd_pcm_open 函数获取。
  • params: 硬件参数结构体,通常由 snd_pcm_hw_params_alloca 分配。
  • access: 访问模式,指定数据在内存中的布局方式。常见的访问模式包括:
    • SND_PCM_ACCESS_MMAP_INTERLEAVED: 交错模式的 mmap 访问。
    • SND_PCM_ACCESS_MMAP_NONINTERLEAVED: 非交错模式的 mmap 访问。
    • SND_PCM_ACCESS_MMAP_COMPLEX: 复杂布局的 mmap 访问。
    • SND_PCM_ACCESS_RW_INTERLEAVED: 交错模式的读写访问。
    • SND_PCM_ACCESS_RW_NONINTERLEAVED: 非交错模式的读写访问。

返回值

  • 成功时返回 0。
  • 失败时返回负的错误代码,例如 -EINVAL(无效参数)或 -ENOSYS(不支持的操作)。

注意事项

  • 在调用 snd_pcm_hw_params_set_access 之前,必须确保硬件参数结构体已正确初始化(通常通过 snd_pcm_hw_params_any 完成)。
  • 某些硬件可能不支持所有访问模式,因此在设置后应检查返回值以确保操作成功。
  • 访问模式的选择会影响数据的读写方式,需根据实际需求选择合适的模式。例如,交错模式适合大多数音频应用,而非交错模式可能适用于多通道音频处理。

snd_pcm_hw_params_malloc 函数解析

snd_pcm_hw_params_malloc 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于动态分配并初始化一个 snd_pcm_hw_params_t 结构体。该结构体用于配置 PCM(Pulse Code Modulation)设备的硬件参数。

函数原型

int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **params);

参数说明

  • params:指向 snd_pcm_hw_params_t 指针的指针,用于存储分配的结构体地址。

返回值

  • 成功时返回 0。
  • 失败时返回负的错误代码。

功能描述

  1. 动态分配一个 snd_pcm_hw_params_t 结构体。
  2. 初始化该结构体,用于后续的硬件参数设置。

注意事项

  1. 分配的内存必须通过 snd_pcm_hw_params_free 释放,以避免内存泄漏。
  2. 该函数仅分配和初始化结构体,具体的硬件参数需要通过其他函数设置,如 snd_pcm_hw_params_any

snd_pcm_hw_params_any 概述

snd_pcm_hw_params_any 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于初始化硬件参数结构体(snd_pcm_hw_params_t),将其设置为声卡支持的默认参数范围。通常在打开 PCM 设备后调用,为后续参数配置提供基础。

函数原型

int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);

参数说明

  • pcm: 指向已打开的 PCM 设备的句柄。
  • params: 待初始化的硬件参数结构体(需提前通过 snd_pcm_hw_params_malloc 分配内存)。

返回值

  • 成功时返回 0,失败时返回负的错误码(如 -ENOMEM 表示内存不足)。

注意事项

  • 内存管理
    需通过 snd_pcm_hw_params_malloc 分配 params 内存,并在使用后调用 snd_pcm_hw_params_free 释放。

  • 错误处理
    检查返回值以确保初始化成功,失败时需处理错误(如释放资源或重试)。

snd_pcm_hw_params_set_access 函数详解

snd_pcm_hw_params_set_access 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于设置 PCM(Pulse Code Modulation)硬件的访问模式。该函数在音频编程中用于配置音频流的访问方式,确保数据在应用程序和音频硬件之间正确传输。

函数原型

int snd_pcm_hw_params_set_access(snd_pcm_t *pcm, 
                                 snd_pcm_hw_params_t *params, 
                                 snd_pcm_access_t access);

参数说明

  • pcm: 指向 PCM 设备的句柄,通过 snd_pcm_open 打开设备时获取。
  • params: 指向硬件参数配置对象的指针,通常由 snd_pcm_hw_params_alloca 分配。
  • access: 指定访问模式,通常为以下值之一:
    • SND_PCM_ACCESS_MMAP_INTERLEAVED: 内存映射交错访问模式。
    • SND_PCM_ACCESS_MMAP_NONINTERLEAVED: 内存映射非交错访问模式。
    • SND_PCM_ACCESS_MMAP_COMPLEX: 复杂内存映射模式。
    • SND_PCM_ACCESS_RW_INTERLEAVED: 读写交错访问模式(最常见)。
    • SND_PCM_ACCESS_RW_NONINTERLEAVED: 读写非交错访问模式。

返回值

  • 成功时返回 0。
  • 失败时返回负的错误码,例如:
    • -EINVAL: 参数无效或不支持的访问模式。
    • -ENOMEM: 内存不足。

常见问题

  1. 访问模式选择

    • SND_PCM_ACCESS_RW_INTERLEAVED 是最常用的模式,适合大多数音频播放和录制场景。
    • 内存映射模式(MMAP)性能更高,但实现更复杂,通常用于低延迟应用。
  2. 错误处理

    • 如果返回错误码,可以通过 snd_strerror(err) 获取错误描述。
    • 检查硬件是否支持所选访问模式,可以通过 snd_pcm_hw_params_test_access 测试。
  3. 参数一致性

    • 在调用 snd_pcm_hw_params_set_access 后,必须调用 snd_pcm_hw_params 应用参数,否则配置不会生效。

snd_pcm_hw_params_set_format 函数说明

snd_pcm_hw_params_set_format 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于设置 PCM(脉冲编码调制)设备的硬件参数中的音频格式。该函数通常在配置音频设备时使用,确保音频数据的格式与硬件支持的格式匹配。

函数原型

int snd_pcm_hw_params_set_format(snd_pcm_t *pcm, 
                                 snd_pcm_hw_params_t *params, 
                                 snd_pcm_format_t format);

参数说明

  • pcm: 指向 PCM 设备的句柄,通常由 snd_pcm_open 打开。
  • params: 指向硬件参数结构的指针,通常由 snd_pcm_hw_params_alloca 分配。
  • format: 要设置的音频格式,类型为 snd_pcm_format_t,例如 SND_PCM_FORMAT_S16_LE(16 位有符号小端格式)。

返回值

  • 成功时返回 0。
  • 失败时返回负的错误代码,例如 -EINVAL(无效参数)或 -ENOSYS(格式不支持)。

支持的常见音频格式

以下是 ALSA 中常见的音频格式枚举值:

  • SND_PCM_FORMAT_S8: 8 位有符号整数。
  • SND_PCM_FORMAT_U8: 8 位无符号整数。
  • SND_PCM_FORMAT_S16_LE: 16 位有符号小端整数。
  • SND_PCM_FORMAT_S16_BE: 16 位有符号大端整数。
  • SND_PCM_FORMAT_S32_LE: 32 位有符号小端整数。
  • SND_PCM_FORMAT_FLOAT_LE: 32 位浮点小端格式。

注意事项

  1. 格式支持检查: 在调用 snd_pcm_hw_params_set_format 之前,可以通过 snd_pcm_hw_params_test_format 检查硬件是否支持目标格式。
  2. 参数应用: 设置格式后,必须调用 snd_pcm_hw_params 将参数应用到设备。
  3. 错误处理: 建议对所有 ALSA 函数调用进行错误检查,确保程序健壮性。

snd_pcm_hw_params_set_rate_near函数

snd_pcm_hw_params_set_rate_near 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于设置音频设备的采样率。该函数尝试将采样率设置为最接近用户指定值的一个有效值,通常用于配置音频流的硬件参数。

函数原型

int snd_pcm_hw_params_set_rate_near(snd_pcm_t *pcm, 
                                    snd_pcm_hw_params_t *params, 
                                    unsigned int *val, 
                                    int *dir);

参数说明

  • pcm:指向 PCM 设备的句柄。
  • params:指向硬件参数结构的指针,用于存储和配置参数。
  • val:指向目标采样率的指针,函数会尝试找到最接近该值的可用采样率,并修改该指针指向的值。
  • dir:指向方向的指针,表示实际设置的采样率与目标值的偏差方向(-1 表示低于目标值,0 表示精确匹配,1 表示高于目标值)。

返回值

  • 成功时返回 0。
  • 失败时返回负的错误代码(如 -EINVAL 表示参数无效)。

注意事项

  • 在调用此函数前,需要先通过 snd_pcm_hw_params_any 初始化参数结构。
  • 实际设置的采样率可能与目标值不同,因此需要检查返回值以确认是否成功。
  • 方向参数 dir 可以帮助了解实际采样率是偏高还是偏低。

snd_pcm_hw_params_set_channels 函数详解

snd_pcm_hw_params_set_channels 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于设置 PCM(Pulse Code Modulation)设备的声道数。该函数通常用于音频应用开发中,配置硬件参数以匹配音频流的声道需求。

函数原型

int snd_pcm_hw_params_set_channels(snd_pcm_t *pcm, 
                                   snd_pcm_hw_params_t *params, 
                                   unsigned int val);

参数说明

  • pcm: PCM 设备的句柄,由 snd_pcm_open 打开时返回。
  • params: 硬件参数结构体,用于存储和配置 PCM 设备的参数。
  • val: 需要设置的声道数(例如,1 表示单声道,2 表示立体声)。

返回值

  • 成功时返回 0。
  • 失败时返回负的错误码(例如 -EINVAL 表示参数无效)。

注意事项

  • 声道数必须与音频文件或流的实际声道数匹配,否则可能导致播放或录制异常。
  • 调用此函数后,需通过 snd_pcm_hw_params 应用参数才能生效。
  • 某些设备可能不支持某些声道数,建议调用 snd_pcm_hw_params_test_channels 测试可用性。

snd_pcm_hw_params 概述

snd_pcm_hw_params 是 ALSA(Advanced Linux Sound Architecture)库中用于设置 PCM(脉冲编码调制)设备硬件参数的结构体。它用于配置音频流的采样率、格式、通道数、缓冲区大小等关键参数,确保音频设备按照预期工作。

    函数原型

    int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **params);
    

    主要功能

    • 参数初始化:从 PCM 设备获取默认硬件参数。
    • 参数设置:设置采样率、格式、缓冲区大小、周期等。
    • 参数验证:检查参数是否被硬件支持。
    • 参数应用:将配置好的参数应用到 PCM 设备。

    参数说明

    • params:指向 snd_pcm_hw_params_t 结构的指针,表示需要释放的硬件参数对象。

    snd_pcm_hw_params_free 函数解析

    snd_pcm_hw_params_free 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于释放与 PCM(Pulse Code Modulation)硬件参数相关的内存资源。该函数通常在配置音频设备硬件参数后调用,以确保资源被正确释放。

    函数原型

    void snd_pcm_hw_params_free(snd_pcm_hw_params_t *params);
    

    参数说明

    • params:指向 snd_pcm_hw_params_t 结构的指针,表示需要释放的硬件参数对象。

    使用场景

    snd_pcm_hw_params_free 通常在以下流程中使用:

    • 调用 snd_pcm_hw_params_malloc 或类似函数分配硬件参数对象。
    • 使用 snd_pcm_hw_params_any 或其他函数初始化硬件参数。
    • 配置采样率、声道数、格式等参数。
    • 调用 snd_pcm_hw_params 将配置应用到 PCM 设备。
    • 最后调用 snd_pcm_hw_params_free 释放资源。

    注意事项

    • 内存泄漏:如果未调用 snd_pcm_hw_params_free,可能会导致内存泄漏。
    • 多次调用:对同一个 params 对象多次调用 snd_pcm_hw_params_free 会导致未定义行为。
    • NULL 检查:虽然传递 NULL 通常是安全的,但建议避免。

    示例代码

    bool initSound()
    {
        LOG_INFO("AlsaRecorder::initSound");
        //硬件参数
        snd_pcm_hw_params_t *hw_params;
    
        char pcm_name_hw[]="hw:1,0";
        char pcm_name_default[]="default";
    
        int err = 0;
        //打开设备
        if((err = snd_pcm_open (&m_captureHandle, pcm_name_hw, SND_PCM_STREAM_CAPTURE, 0)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_open: %1 throw error: %2")
                      .arg(pcm_name_hw)
                      .arg(snd_strerror(err)));
            if((err = snd_pcm_open (&m_captureHandle, pcm_name_default, SND_PCM_STREAM_CAPTURE, 0)) < 0)
            {
                LOG_ERROR(QString("snd_pcm_open: %1 throw error: %2")
                          .arg(pcm_name_default)
                          .arg(snd_strerror(err)));
                return false;
            }
        }
        //为参数分配空间
        if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_hw_params_malloc: %1").arg(snd_strerror(err)));
            return false;
        }
        //填充参数空间
        if((err = snd_pcm_hw_params_any (m_captureHandle, hw_params)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_hw_params_any: %1").arg(snd_strerror(err)));
            return false;
        }
        //设置数据访问方式
        if((err = snd_pcm_hw_params_set_access(m_captureHandle,hw_params,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_hw_params_set_access: %1").arg(snd_strerror(err)));
            return false;
        }
        //设置格式
        if(m_byteSample == 2)
        {
            if((err = snd_pcm_hw_params_set_format(m_captureHandle, hw_params, SND_PCM_FORMAT_S16_LE)) < 0)
            {
                LOG_ERROR(QString("snd_pcm_hw_params_set_format1: %1").arg(snd_strerror(err)));
                return false;
            }
        }
        else if(m_byteSample == 4)
        {
            if((err = snd_pcm_hw_params_set_format(m_captureHandle, hw_params, SND_PCM_FORMAT_S32_LE)) < 0)
            {
                LOG_ERROR(QString("snd_pcm_hw_params_set_format2: %1").arg(snd_strerror(err)));
                return false;
            }
        }
        else
            return false;
        //设置采样率
        if ((err = snd_pcm_hw_params_set_rate_near (m_captureHandle, hw_params, (unsigned int *) &m_sampleSize, 0)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_hw_params_set_rate_near: %1").arg(snd_strerror(err)));
            return false;
        }
        //设置通道
        if ((err = snd_pcm_hw_params_set_channels (m_captureHandle, hw_params, m_channels)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_hw_params_set_channels: %1").arg(snd_strerror(err)));
            return false;
        }
        //设置参数
        if ((err = snd_pcm_hw_params (m_captureHandle, hw_params)) < 0)
        {
            LOG_ERROR(QString("snd_pcm_hw_params: %1").arg(snd_strerror(err)));
            return false;
        }
        snd_pcm_hw_params_free (hw_params);
        return true;
    }

    snd_pcm_set_params 函数概述

    snd_pcm_set_params 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于配置 PCM(Pulse Code Modulation)设备的参数。该函数通常用于设置音频流的格式、采样率、通道数、缓冲区大小等参数。

    函数原型

    int snd_pcm_set_params(snd_pcm_t *pcm,
                           snd_pcm_format_t format,
                           snd_pcm_access_t access,
                           unsigned int channels,
                           unsigned int rate,
                           int soft_resample,
                           unsigned int latency);
    

    参数说明

    • pcm: PCM 设备的句柄,通常由 snd_pcm_open 打开后获得。
    • format: 音频数据的格式,如 SND_PCM_FORMAT_S16_LE(16位有符号小端格式)。
    • access: 访问模式,如 SND_PCM_ACCESS_RW_INTERLEAVED(交错读写模式)。
    • channels: 音频通道数,如 2(立体声)。
    • rate: 采样率,如 44100(44.1kHz)。
    • soft_resample: 是否启用软件重采样(1 启用,0 禁用)。
    • latency: 期望的延迟时间(单位为微秒)。

    返回值

    成功时返回 0,失败时返回负的错误代码。

    使用示例

    以下是一个简单的示例代码,展示如何使用 snd_pcm_set_params 配置 PCM 设备:

    #include <alsa/asoundlib.h>
    
    int main() {
        snd_pcm_t *pcm_handle;
        int err;
    
        // 打开 PCM 设备
        err = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
        if (err < 0) {
            fprintf(stderr, "无法打开 PCM 设备: %s\n", snd_strerror(err));
            return -1;
        }
    
        // 设置 PCM 参数
        err = snd_pcm_set_params(pcm_handle,
                                 SND_PCM_FORMAT_S16_LE,
                                 SND_PCM_ACCESS_RW_INTERLEAVED,
                                 2,
                                 44100,
                                 1,
                                 500000); // 500ms 延迟
        if (err < 0) {
            fprintf(stderr, "无法设置 PCM 参数: %s\n", snd_strerror(err));
            return -1;
        }
    
        // 使用 PCM 设备进行播放或其他操作
    
        // 关闭 PCM 设备
        snd_pcm_close(pcm_handle);
        return 0;
    }
    

    常见问题

    1. 参数不兼容: 某些参数组合可能不被硬件支持,需检查硬件规格。
    2. 延迟设置不合理: 过小的延迟可能导致缓冲区不足,过大的延迟会增加播放延迟。
    3. 软件重采样: 启用软件重采样会增加 CPU 负载,但能解决硬件不支持特定采样率的问题。

    替代函数

    如果需要对参数进行更精细的控制,可以使用以下函数替代:

    • snd_pcm_hw_params_set_format
    • snd_pcm_hw_params_set_access
    • snd_pcm_hw_params_set_channels
    • snd_pcm_hw_params_set_rate

    这些函数需要先初始化 snd_pcm_hw_params_t 结构体并分配参数空间。

    snd_pcm_readi 函数简介

    snd_pcm_readi 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于从 PCM(Pulse Code Modulation)设备的输入缓冲区读取音频数据。该函数适用于交错模式(interleaved)的音频数据流。

    函数原型

    snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm, 
                                    void *buffer, 
                                    snd_pcm_uframes_t size);
    

    参数说明

    • pcm:指向 PCM 设备句柄的指针。
    • buffer:用于存储读取的音频数据的缓冲区。
    • size:请求读取的帧数(每帧包含多个通道的样本)。

    返回值

    • 成功时返回实际读取的帧数(可能小于请求的帧数)。
    • 失败时返回负的错误代码(例如 -EPIPE 表示缓冲区欠载)。

    使用场景

    snd_pcm_readi 通常用于音频采集应用,例如录音或实时音频处理。需要配合其他 ALSA 函数(如 snd_pcm_opensnd_pcm_prepare)使用。

    常见问题

    1. 返回值错误

      • -EBADFD:PCM 设备未正确配置或未处于运行状态。
      • -EPIPE:缓冲区欠载(overrun 或 underrun),需调用 snd_pcm_recover 恢复。
    2. 性能优化

      • 使用较大的缓冲区减少中断频率。
      • 确保实时线程优先级足够高以避免延迟。
    3. 数据格式

      • 必须与 snd_pcm_hw_params_set_format 设置的格式一致(例如 SND_PCM_FORMAT_S16_LE 表示 16 位小端有符号整数)。

    替代函数

    • 非交错模式:使用 snd_pcm_readn
    • 更高级的异步接口:考虑 snd_async_add_pcm_handler

      snd_pcm_writei 函数概述

      snd_pcm_writei 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于将音频数据从应用程序缓冲区写入 PCM(Pulse Code Modulation)设备。该函数以交错模式(interleaved)处理多声道音频数据,适用于实时音频播放或录制场景。

      函数原型

      snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, 
                                       const void *buffer, 
                                       snd_pcm_uframes_t size);
      

      参数说明

      • pcm:指向 PCM 设备的句柄。
      • buffer:包含音频数据的缓冲区指针,数据需为交错格式。
      • size:请求写入的帧数(每帧包含所有声道的样本)。

      返回值

      • 成功时返回实际写入的帧数(可能小于请求的帧数)。
      • 失败时返回负的错误码(如 -EPIPE 表示设备状态异常)。

      使用步骤

      1.初始化 PCM 设备

      需先调用 snd_pcm_open 打开设备,并通过 snd_pcm_set_params 设置参数(采样率、格式、声道数等)。

      snd_pcm_t *handle;
      snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
      snd_pcm_set_params(handle, SND_PCM_FORMAT_S16, 
      SND_PCM_ACCESS_RW_INTERLEAVED, 2, 44100, 1, 500000);
      
      2.准备音频数据

      确保缓冲区数据格式与设备参数匹配。例如,16 位有符号整数、立体声交错排列。

      short buffer[FRAMES * 2]; // 立体声:每帧 2 个样本(左、右)
      
      3.写入数据

      循环调用 snd_pcm_writei 写入数据,并处理可能的错误(如欠载)。

      snd_pcm_sframes_t frames = snd_pcm_writei(handle, buffer, FRAMES);
      if (frames < 0) {
          frames = snd_pcm_recover(handle, frames, 0); // 尝试恢复
      }
      
      4.清理资源

      关闭设备并释放资源。

      snd_pcm_close(handle);
      

      常见问题与解决

      欠载(Underrun) 当应用程序写入速度不够快时触发。可通过增加缓冲区大小或优化数据处理逻辑缓解。

      if (frames == -EPIPE) {
          snd_pcm_prepare(handle); // 重新准备设备
      }
      

      帧数不匹配 实际写入帧数可能小于请求值。需检查设备状态或调整缓冲区大小。

      性能优化建议

      • 使用更大的缓冲区以减少欠载概率,但会增加延迟。
      • 实时应用可考虑线程优先级调整(如 sched_setscheduler)。
      • 定期调用 snd_pcm_avail_update 检查可用空间。

      snd_pcm_prepare 函数概述

      snd_pcm_prepare 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于准备 PCM(Pulse Code Modulation)设备,使其处于可启动或可恢复状态。通常在启动、停止或暂停 PCM 流后调用该函数,以确保设备可以正确重新开始数据传输。

      函数原型

      int snd_pcm_prepare(snd_pcm_t *pcm_handle);
      

      参数

      • pcm_handle:指向已打开的 PCM 设备的句柄。

      返回值

      • 成功时返回 0,失败时返回负的错误代码。

      使用场景

      snd_pcm_prepare 通常在以下情况下调用:

      1. 在调用 snd_pcm_start 之前,确保 PCM 设备处于就绪状态。
      2. 在调用 snd_pcm_pause 暂停后恢复播放或录制时。
      3. 在调用 snd_pcm_dropsnd_pcm_drain 后重新启动 PCM 流。

      示例代码

      #include <alsa/asoundlib.h>
      
      int main() {
          snd_pcm_t *pcm_handle;
          int err;
      
          // 打开 PCM 设备
          err = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
          if (err < 0) {
              fprintf(stderr, "无法打开 PCM 设备: %s\n", snd_strerror(err));
              return -1;
          }
      
          // 设置硬件参数(省略部分代码)
      
          // 准备 PCM 设备
          err = snd_pcm_prepare(pcm_handle);
          if (err < 0) {
              fprintf(stderr, "无法准备 PCM 设备: %s\n", snd_strerror(err));
              snd_pcm_close(pcm_handle);
              return -1;
          }
      
          // 启动 PCM 设备
          err = snd_pcm_start(pcm_handle);
          if (err < 0) {
              fprintf(stderr, "无法启动 PCM 设备: %s\n", snd_strerror(err));
              snd_pcm_close(pcm_handle);
              return -1;
          }
      
          // 其他操作(如写入数据)
      
          // 关闭 PCM 设备
          snd_pcm_close(pcm_handle);
          return 0;
      }
      

      常见错误处理

      • EBADFD:PCM 设备未处于正确的状态(如未正确设置参数)。
      • ENODEV:设备已断开连接或不可用。
      • EIO:硬件或驱动程序发生 I/O 错误。

      可以通过 snd_strerror(err) 获取错误描述。

      注意事项

      1. 调用 snd_pcm_prepare 后,PCM 设备会进入 SND_PCM_STATE_PREPARED 状态。
      2. 在准备设备前,必须确保硬件参数(如采样率、格式、通道数等)已正确设置。
      3. 如果在 snd_pcm_writeisnd_pcm_readi 中发生欠载或过载错误,可能需要重新调用 snd_pcm_prepare 恢复设备状态。

      snd_pcm_recover 函数解析

      snd_pcm_recover 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于从 PCM(Pulse Code Modulation)设备的错误状态中恢复。以下是对该函数的详细说明和用法:

      函数原型

      int snd_pcm_recover(snd_pcm_t *pcm, int err, int silent);
      

      参数说明

      • pcm:指向 snd_pcm_t 对象的指针,表示 PCM 设备。
      • err:错误码,通常由 ALSA 函数(如 snd_pcm_writeisnd_pcm_readi)返回。
      • silent:控制是否输出错误信息。设置为 1 时,不输出错误信息;设置为 0 时,输出错误信息。

      返回值

      • 成功时返回 0。
      • 失败时返回负的错误码。

      常见错误码

      • -EPIPE:表示 underrun(播放时)或 overrun(录音时)。
      • -ESTRPIPE:表示 PCM 设备被挂起(通常由系统事件引起,如 USB 设备断开连接)。

      使用方法

      以下是一个典型的使用场景,展示如何从错误中恢复并继续播放音频:

      snd_pcm_t *pcm_handle;
      int err = snd_pcm_writei(pcm_handle, buffer, frames);
      if (err < 0) {
          err = snd_pcm_recover(pcm_handle, err, 0);
          if (err < 0) {
              fprintf(stderr, "无法恢复 PCM 设备: %s\n", snd_strerror(err));
              exit(EXIT_FAILURE);
          }
      }
      

      注意事项

      • 错误处理snd_pcm_recover 只能处理特定的错误(如 -EPIPE-ESTRPIPE)。对于其他错误,可能需要重新初始化 PCM 设备。
      • 性能影响:频繁调用 snd_pcm_recover 可能会影响音频流的性能,应尽量避免错误的发生。
      • 线程安全:在多线程环境中使用时,需要确保对 PCM 设备的访问是线程安全的。

      替代方案

      如果 snd_pcm_recover 无法恢复设备,可以尝试以下方法:

      snd_pcm_drop(pcm_handle);
      snd_pcm_prepare(pcm_handle);
      

      通过以上方法,可以有效地从 PCM 设备的错误状态中恢复,确保音频流的正常运行。

      snd_pcm_close 函数概述

      snd_pcm_close 是 ALSA(Advanced Linux Sound Architecture)库中的一个函数,用于关闭已打开的 PCM(脉冲编码调制)设备。该函数释放与 PCM 设备关联的所有资源,确保正确终止音频流。

      函数原型

      int snd_pcm_close(snd_pcm_t *pcm);
      

      参数说明

      • pcm:指向已打开的 PCM 设备的句柄(类型为 snd_pcm_t*)。

      返回值

      • 成功时返回 0
      • 失败时返回负的错误代码(如 -EBADFD 表示无效的 PCM 句柄)。

      使用场景

      snd_pcm_close 通常在以下情况下调用:

      • 音频播放或录制完成后,需要释放资源。
      • 程序退出前,确保所有音频设备已正确关闭。
      • 发生错误时,清理已打开的 PCM 设备。

      注意事项

      1. 资源释放

        • 调用 snd_pcm_close 后,pcm_handle 将不再有效,后续操作会导致未定义行为。
        • 确保在关闭前停止所有音频流(如调用 snd_pcm_dropsnd_pcm_drain)。
      2. 错误处理

        • 检查返回值以确认关闭操作是否成功。
        • 使用 snd_strerror 获取可读的错误信息。
      3. 多线程环境

        • 在多线程程序中,确保没有其他线程正在使用 PCM 设备时再调用 snd_pcm_close
      4. 关联函数

        • snd_pcm_open:打开 PCM 设备。
        • snd_pcm_drain:等待所有挂起的音频帧完成。
        • snd_pcm_drop:立即停止音频流。

      常见错误

      • -EBADFD:传入的 pcm_handle 无效或已关闭。
      • -ENOMEM:内存不足,无法完成操作。
      • -EIO:底层硬件或驱动程序错误。

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值