ALSA的hw接口是否绕过调音台?

问题描述

我正在通过libasound2-dev:armhf 1.1.8-1+rpt1使用ALSA。我已经卸载了pulseAudio,因为这是针对RaspBerry Pi 4上的单设备,单应用程序的设备。

我以以下方式使用libasound

  • 使用SND_PCM_STREAM_CAPTURE遍历所有卡和设备
  • 找到第一个snd_ctl_pcm_info不会失败的第一个-ENOENT呼叫时停止-这正是arecord的工作方式
  • 通过hw:2,0打开snd_pcm_open上的USB麦克风(对我来说)总是
  • 设置一些参数-单声道44.1 kHz S16_LE
  • 在同时具有snd_ctl_elem_write接口的Auto Gain ControlMic Capture Volume元素上调用SND_CTL_ELEM_IFACE_mixer –这些值似乎在以后的读取中仍然存在
  • 基于ALSA test/pcm.c中的“直接写”访问模式来阻止mmap读取

捕获的数据看似理智,但非常安静(从未超过2000/65535)。增益似乎并未注意上述元素设置。这是因为这些元素在混合器界面上,并且hw:绕过了混合器吗?

代码很长,但这是设置元素的部分:

static void describe_set_elems(const CaptureContext *restrict ctx)
{
    snd_ctl_elem_list_t *elements;
    snd_ctl_elem_list_alloca(&elements);
    check_snd(snd_ctl_elem_list(ctx->ctl,elements));

    int n_elements = snd_ctl_elem_list_get_count(elements);
    check_snd(snd_ctl_elem_list_alloc_space(elements,n_elements));

    // It's goofy that we have to call this a second time,but it's needed
    check_snd(snd_ctl_elem_list(ctx->ctl,elements));
    assert(n_elements == snd_ctl_elem_list_get_count(elements));

    snd_ctl_elem_id_t *id;
    snd_ctl_elem_id_alloca(&id);
    assert(id);

    snd_ctl_elem_info_t *elem;
    snd_ctl_elem_info_alloca(&elem);
    assert(elem);

    snd_ctl_elem_value_t *value;
    snd_ctl_elem_value_alloca(&value);
    assert(value);

    bool vol_set = false,agc_set = false;

    puts(
        "Control elements ---------------------------------------------------\n"
    );

    for (int e = 0; e < n_elements; e++)
    {
        snd_ctl_elem_list_get_id(elements,e,id);
        snd_ctl_elem_info_set_id(elem,id);
        check_snd(snd_ctl_elem_info(ctx->ctl,elem));

        snd_ctl_elem_type_t type = snd_ctl_elem_info_get_type(elem);

        const char *item_name;
        unsigned items;
        if (type == SND_CTL_ELEM_TYPE_ENUMERATED)
        {
            item_name = snd_ctl_elem_info_get_item_name(elem);
            items = snd_ctl_elem_info_get_items(elem);
        }
        else
        {
            item_name = "<non-enumerated>";
            items = 0;
        }

        char min[32],max[32],step[32];
        long max_int;
        switch (type)
        {
        case SND_CTL_ELEM_TYPE_INTEGER:
            max_int = snd_ctl_elem_info_get_max(elem);
            snprintf(min,32,"%ld",snd_ctl_elem_info_get_min(elem));
            snprintf(max,max_int);
            snprintf(step,snd_ctl_elem_info_get_step(elem));
            break;
        case SND_CTL_ELEM_TYPE_integer64:
            snprintf(min,"%lld",snd_ctl_elem_info_get_min64(elem));
            snprintf(max,snd_ctl_elem_info_get_max64(elem));
            snprintf(step,snd_ctl_elem_info_get_step64(elem));
            break;
        default:
            strncpy(min,"<non-integer>",32);
            strncpy(max,32);
            strncpy(step,32);
        }

        const char *name = snd_ctl_elem_info_get_name(elem);
        bool readable = snd_ctl_elem_info_is_readable(elem),writable = snd_ctl_elem_info_is_writable(elem);
        const int index = snd_ctl_elem_info_get_index(elem);

        printf(
            "  name       : %s\n"
            "  type       : %s\n"
            "  numid      : %u\n"
            "  count      : %u\n"
            "  device     : %u\n"
            "  subdevice  : %u\n"
            "  dimension  : %d\n"
            "  dimensions : %d\n"
            "  index      : %u\n"
            "  interface  : %s\n"
            "  item name  : %s\n"
            "  items      : %u\n"
            "  min        : %s\n"
            "  max        : %s\n"
            "  step       : %s\n"
            "  owner      : %d\n"
            "  inactive   : %d\n"
            "  locked     : %d\n"
            "  is owner        : %d\n"
            "  is user         : %d\n"
            "  is readable     : %d\n"
            "  is writable     : %d\n"
            "  is volatile     : %d\n"
            "  tlv commandable : %d\n"
            "  tlv readable    : %d\n"
            "  tlv writeable   : %d\n",name,snd_ctl_elem_type_name(
                snd_ctl_elem_info_get_type(elem)
            ),snd_ctl_elem_info_get_numid(elem),snd_ctl_elem_info_get_count(elem),snd_ctl_elem_info_get_device(elem),snd_ctl_elem_info_get_subdevice(elem),snd_ctl_elem_info_get_dimension(elem,e),snd_ctl_elem_info_get_dimensions(elem),index,snd_ctl_elem_iface_name(
                snd_ctl_elem_info_get_interface(elem)
            ),item_name,items,min,max,step,snd_ctl_elem_info_get_owner(elem),snd_ctl_elem_info_is_inactive(elem),snd_ctl_elem_info_is_locked(elem),snd_ctl_elem_info_is_owner(elem),snd_ctl_elem_info_is_user(elem),readable,writable,snd_ctl_elem_info_is_volatile(elem),snd_ctl_elem_info_is_tlv_commandable(elem),snd_ctl_elem_info_is_tlv_readable(elem),snd_ctl_elem_info_is_tlv_writable(elem)
        );

        snd_ctl_elem_value_set_id(value,id);

        bool is_agc = false,is_vol = false;
        if (!strcmp(name,"Auto Gain Control"))
            is_agc = true;
        else if (!strcmp(name,"Mic Capture Volume"))
            is_vol = true;
        if (is_vol || is_agc)
        {
            assert(writable);

            if (is_vol)
            {
                snd_ctl_elem_value_set_integer(
                    value,(long)(VOLUME * max_int)
                );
                vol_set = true;
            }
            else if (is_agc)
            {
                snd_ctl_elem_value_set_boolean(value,AGC);
                agc_set = true;
            }

            check_snd(snd_ctl_elem_write(ctx->ctl,value));
        }

        if (readable)
        {
            check_snd(snd_ctl_elem_read(ctx->ctl,value));

            char val_str[64];

            switch (type)
            {
            case SND_CTL_ELEM_TYPE_INTEGER:
                snprintf(
                    val_str,64,snd_ctl_elem_value_get_integer(value,index)
                );
                break;

            case SND_CTL_ELEM_TYPE_integer64:
                snprintf(
                    val_str,snd_ctl_elem_value_get_integer64(value,index)
                );
                break;

            case SND_CTL_ELEM_TYPE_BOOLEAN:
                strncpy(
                    val_str,snd_ctl_elem_value_get_boolean(value,index)
                    ? "TRUE" : "FALSE",64
                );
                break;

            default:
                strncpy(val_str,"Unsupported type",64);
                break;
            }

            printf(
                "  value      : %s\n",val_str
            );
        }

        putchar('\n');
    }

    assert(vol_set);
    assert(agc_set);
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)