首页 > 解决方案 > ALSA 的依赖问题(libao 和 sndfile)

问题描述

我编写了一个小程序来使用来自 github 的参考来播放 PCM 音频文件,并对我的应用程序稍作修改。该程序编译良好,但我遇到了一些关于依赖项和 ALSA 设备的运行时问题。

我收到的错误是:

ERROR: Failed to load plugin /usr/lib/x86_64-linux-gnu/ao/plugins-4/libsndio.so => dlopen() failed
ERROR: Failed to load plugin /usr/lib/x86_64-linux-gnu/ao/plugins-4/libnas.so => dlopen() failed
ao_alsa WARNING: Unable to open surround playback.  Trying default device...
ALSA lib pcm_dmix.c:1089:(snd_pcm_dmix_open) unable to open slave
ao_alsa ERROR: Unable to open ALSA device 'default' for playback => No such file or directory

我一直在研究许多不同的解决方案,但似乎都没有工作,包括在 /etc/modprobe.d 中的 alsa.conf 文件中添加一行(但是,这些解决方案建议在我使用 AMD 时添加一行引用 intel设置。

这是完整的代码:

/*
 *
 * ao_example.c
 *
 *     Written by Stan Seibert - July 2001
 *
 * Legal Terms:
 *
 *     This source file is released into the public domain.  It is
 *     distributed without any warranty; without even the implied
 *     warranty * of merchantability or fitness for a particular
 *     purpose.
 *
 * Function:
 *
 *     This program opens the default driver and plays a 440 Hz tone for
 *     one second.
 *
 * Compilation command line (for Linux systems):
 *
 *     gcc -o ao_example ao_example.c -lao -ldl -lm -lsndfile
 *
 */

#include <stdio.h>
#include <string.h>
#include <ao/ao.h>
#include <math.h>
#include <sndfile.h>

#define BUF_SIZE 4096

static void clean(ao_device *device, SNDFILE *file){
    ao_close(device);
    sf_close(file);
    ao_shutdown();
}

int main(int argc, char **argv)
{
    ao_device *device;
    ao_sample_format format;
    unsigned long count;
    int default_driver;
    short *buffer;
    int buf_size;
    int sample;
    int i;
    //FILE *fp;
    SF_INFO sfinfo;

    if (argc != 2){
        printf("usage: %s <filename>\n", argv[0]);
        exit(1);
    }

    /* -- Initialize -- */

    fprintf(stderr, "libao example program\n");

    SNDFILE *fp = sf_open(argv[1], SFM_READ, &sfinfo);

    // fp = fopen(argv[1], "rb");
    if (fp == NULL){
        printf("Cannot open %s.\n", argv[1]);
        exit(1);
    }

    printf("samples: %d\n", sfinfo.frames);
    printf("sample rate: %d\n", sfinfo.samplerate);
    printf("Channels: %d\n", sfinfo.channels);

    ao_initialize();

    /* -- Setup for default driver -- */

    default_driver = ao_default_driver_id();

    switch(sfinfo.format & SF_FORMAT_SUBMASK){
        case SF_FORMAT_PCM_16:
            format.bits = 16;
            break;
        case SF_FORMAT_PCM_24:
            format.bits = 24;
            break;
        case SF_FORMAT_PCM_32:
            format.bits = 32;
            break;
        case SF_FORMAT_PCM_S8:
            format.bits = 8;
            break;
        case SF_FORMAT_PCM_U8:
            format.bits = 8;
            break;
        default:
            format.bits = 24;
            break;
    }

    format.channels = sfinfo.channels;
    format.rate = sfinfo.samplerate;
    format.byte_format = AO_FMT_LITTLE;
    // format.byte_format = AO_FMT_NATIVE;
    format.matrix = 0;

    // memset(&format, 0, sizeof(format));
    // format.bits = 24;
    // format.channels = 16;
    // format.rate = 48000;
    // format.byte_format = AO_FMT_LITTLE;

    /* -- Open driver -- */
    device = ao_open_live(default_driver, &format, NULL /* no options */);

    if (device == NULL) {
        fprintf(stderr, "Error opening device.\n");
        return 1;
    }
    
    // fseek(fp, 0, SEEK_END);
    // count = ftell(fp);
    // fseek(fp, 0, SEEK_SET);

    // // printf("count: %ld\n", count);

    buffer = calloc(BUF_SIZE, sizeof(short));

    while(1){
        int read = sf_read_short(fp, buffer, BUF_SIZE);

        if (ao_play(device, (char *) buffer, (uint_32)(read * sizeof(short))) == 0){
            printf("ao_play: failed\n");
            clean(device, fp);
            break;
        }
    }

    clean(device, fp);

  return 0;
}

我希望其他人也遇到过同样的麻烦,并且可以阐明解决方案。谢谢你。

标签: clinuxaudioalsalibsndfile

解决方案


总结讨论:

问题似乎不在于代码本身,而在于libao配置。

根据libao 文档,该库尝试按如下方式确定默认驱动程序:

在没有配置文件显式识别默认驱动程序的情况下,库将尝试检测合适的默认驱动程序。它通过测试每个可用的实时输出驱动程序(使用 ao_plugin_test())并找到具有最高优先级的驱动程序(参见 ao_info 结构)来实现这一点。优先级为 0 的驱动程序,例如 null 和文件输出驱动程序,永远不会被选为默认值。

错误消息表明已尝试了包括和nas在内的多个驱动程序。手动选择驱动程序而不是使用可以解决问题。sndioalsaao_driver_id(...)ao_default_driver_id()

ao_open_live(...)可以通过使用 获取相应的错误号来调查打开设备的更多问题printf("errno %d\n", errno);。输出可以解释如下:

AO_ENODRIVER (1) - No driver corresponds to driver_id.
AO_ENOTLIVE (3) - This driver is not a live output device.
AO_EBADOPTION (4) - A valid option key has an invalid value.
AO_EOPENDEVICE (5) - Cannot open the device (for example, if /dev/dsp cannot be opened for writing).
AO_EFAIL (100) - Any other cause of failure.

除此之外,可以在~/.libao配置文件中启用调试以获取更多信息。


推荐阅读