Audio:Android-TinyAlsa架构 Mixer API

        Android中对音频多声道数据的配置binary tinymix是tinyplay执行前必要的步骤,对tinymix的源码进行check在整合tinyalsa相关通道配置以及流程上是非常有必要的。tinymix梳理之后还是比较简单的,主要有mixer_open, mixer_close, tinymix_list_controls, tinymix_detail_control, tinymix_set_value这个几个方法。

1.tinymix.c

file path: external/tinyalsa/tinymix.c

int main(int argc, char **argv)
{
    struct mixer *mixer;
    int card = 0;
    int ret = 0;

    while (1) {
        int option_index = 0;
        int option_char = 0;

        option_char = getopt_long(argc, argv, tinymix_short_options,
                                  tinymix_long_options, &option_index);
        if (option_char == -1)
            break;

        switch (option_char) {
        case 'D':
            ...
    }


    //mixer_open打开对应card的mixer配置,默认为0
    mixer = mixer_open(card);
    if (!mixer) {
        fprintf(stderr, "Failed to open mixer\n");
        return ENODEV;
    }

    if (argc == optind) {
        printf("Mixer name: '%s'\n", mixer_get_name(mixer));
        //查看所有的mixer配置参数
        tinymix_list_controls(mixer);
    } else if (argc == optind + 1) {
        //查看某一项mixer配置参数
        ret = tinymix_detail_control(mixer, argv[optind], !g_value_only, !g_value_only);
    } else if (argc >= optind + 2) {
        //通过mixer设置通道参数
        ret = tinymix_set_value(mixer, argv[optind], &argv[optind + 1], argc - optind - 1);
    }

    //最后通过mixer_close关闭mixer配置
    mixer_close(mixer);

    return ret;
}

2.tinytest.c

        参考tinymix.c写入相关的音频配置参数S_NORMAL_AP01_C_CODEC SWITCH 和 S_VOICE_C_CODEC SWITCH都写为1,on的状态。

int main(int argc, char **argv)
{
    struct mixer *mixer;
    int card = 0;
    int i;
    char *control1 = "S_NORMAL_AP01_C_CODEC SWITCH";
    char *control2 = "S_VOICE_C_CODEC SWITCH";
    char *values = "1";

    if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) {
        argv++;
        if (argv[1]) {
            card = atoi(argv[1]);
            argv++;
            argc -= 2;
        } else {
            argc -= 1;
        }
    }

    mixer = mixer_open(card);
    if (!mixer) {
        DEBUG_Log_Err("Failed to open mixer\n");
        return EXIT_FAILURE;
    }

    DEBUG_Log_Info("shengjie-setmixer");
    tinymix_set_value(mixer, control1, &values, 1);
    tinymix_set_value(mixer, control2, &values, 1);

    mixer_close(mixer);

    return 0;
}

3.tinymix-tinymix_list_controls

        这边可以显示出所有的mixer配置的音频参数通道以及通过tinymix_detail_control查看通道现在的值,具体使用方法如下图所示。

static void tinymix_list_controls(struct mixer *mixer)
{
    struct mixer_ctl *ctl;
    const char *name, *type;
    unsigned int num_ctls, num_values;
    unsigned int i;

    num_ctls = mixer_get_num_ctls(mixer);

    printf("Number of controls: %u\n", num_ctls);

    if (g_tabs_only)
        printf("ctl\ttype\tnum\tname\tvalue");
    else
        printf("ctl\ttype\tnum\t%-40s value\n", "name");
    if (g_all_values)
        printf("\trange/values\n");
    else
        printf("\n");
    for (i = 0; i < num_ctls; i++) {
        ctl = mixer_get_ctl(mixer, i);

        name = mixer_ctl_get_name(ctl);
        type = mixer_ctl_get_type_string(ctl);
        num_values = mixer_ctl_get_num_values(ctl);
        if (g_tabs_only)
            printf("%d\t%s\t%d\t%s\t", i, type, num_values, name);
        else
            printf("%d\t%s\t%d\t%-40s ", i, type, num_values, name);
        tinymix_detail_control(mixer, name, 0, g_all_values);
    }
}

4.tinymix-tinymix_detail_control

        tinymix_detail_control接口目的就是查看具体音频通道的配置信息,具体使用方法如下图所示。

static int tinymix_detail_control(struct mixer *mixer, const char *control,
                                  int prefix, int print_all)
{
    struct mixer_ctl *ctl;
    enum mixer_ctl_type type;
    unsigned int num_values;
    unsigned int i;
    int min, max;
    int ret;
    char *buf = NULL;
    size_t len;
    unsigned int tlv_header_size = 0;
    const char *space = g_tabs_only ? "\t" : " ";

    if (isdigit(control[0]))
        ctl = mixer_get_ctl(mixer, atoi(control));
    else
        ctl = mixer_get_ctl_by_name(mixer, control);

    if (!ctl) {
        fprintf(stderr, "Invalid mixer control: %s\n", control);
        return ENOENT;
    }

    type = mixer_ctl_get_type(ctl);
    num_values = mixer_ctl_get_num_values(ctl);

    if (type == MIXER_CTL_TYPE_BYTE) {
        if (mixer_ctl_is_access_tlv_rw(ctl)) {
            tlv_header_size = TLV_HEADER_SIZE;
        }
        buf = calloc(1, num_values + tlv_header_size);
        if (buf == NULL) {
            fprintf(stderr, "Failed to alloc mem for bytes %d\n", num_values);
            return ENOENT;
        }

        len = num_values;
        ret = mixer_ctl_get_array(ctl, buf, len + tlv_header_size);
        if (ret < 0) {
            fprintf(stderr, "Failed to mixer_ctl_get_array\n");
            free(buf);
            return ENOENT;
        }
    }


    printf("shengjie-%s, num:%d", mixer_ctl_get_name(ctl), num_values);
    if (prefix)
        printf("%s:%s", mixer_ctl_get_name(ctl), space);

    for (i = 0; i < num_values; i++) {
        switch (type)
        {
        case MIXER_CTL_TYPE_INT:
            printf("%d", mixer_ctl_get_value(ctl, i));
            break;
        case MIXER_CTL_TYPE_BOOL:
            printf("%s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
            break;
        case MIXER_CTL_TYPE_ENUM:
            tinymix_print_enum(ctl, space, print_all);
            break;
        case MIXER_CTL_TYPE_BYTE:
            /* skip printing TLV header if exists */
            printf(" %02x", buf[i + tlv_header_size]);
            break;
        default:
            printf("unknown");
            break;
        }

        if (i < num_values - 1)
            printf("%s", space);
    }

    if (print_all) {
        if (type == MIXER_CTL_TYPE_INT) {
            min = mixer_ctl_get_range_min(ctl);
            max = mixer_ctl_get_range_max(ctl);
            printf("%s(dsrange %d->%d)", space, min, max);
        }
    }

    free(buf);

    printf("\n");
    return 0;
}

 

 

5.tinymix-tinymix_set_value

        tinymix_set_value接口在tinymix使用中应该是最重要的,所有的配置都需要这个接口进行控制,应用层或Audio HAL层调用的set audio mixer参数都要通过mixer_open、tinymix_set_value、mixer_close接口。下图所示是包含配置增益的参数配置check。

static int tinymix_set_value(struct mixer *mixer, const char *control,
                             char **values, unsigned int num_values)
{
    struct mixer_ctl *ctl;
    enum mixer_ctl_type type;
    unsigned int num_ctl_values;
    unsigned int i;

    if (isdigit(control[0]))
        ctl = mixer_get_ctl(mixer, atoi(control));
    else
        ctl = mixer_get_ctl_by_name(mixer, control);

    if (!ctl) {
        fprintf(stderr, "Invalid mixer control: %s\n", control);
        return ENOENT;
    }

    type = mixer_ctl_get_type(ctl);
    num_ctl_values = mixer_ctl_get_num_values(ctl);

    if (type == MIXER_CTL_TYPE_BYTE) {
        tinymix_set_byte_ctl(ctl, values, num_values);
        return ENOENT;
    }

    if (isdigit(values[0][0])) {
        if (num_values == 1) {
            /* Set all values the same */
            int value = atoi(values[0]);

            for (i = 0; i < num_ctl_values; i++) {
                if (mixer_ctl_set_value(ctl, i, value)) {
                    fprintf(stderr, "Error: invalid value\n");
                    return EINVAL;
                }
            }
        } else {
            /* Set multiple values */
            if (num_values > num_ctl_values) {
                fprintf(stderr,
                        "Error: %u values given, but control only takes %u\n",
                        num_values, num_ctl_values);
                return EINVAL;
            }
            for (i = 0; i < num_values; i++) {
                if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) {
                    fprintf(stderr, "Error: invalid value for index %d\n", i);
                    return EINVAL;
                }
            }
        }
    } else {
        if (type == MIXER_CTL_TYPE_ENUM) {
            if (num_values != 1) {
                fprintf(stderr, "Enclose strings in quotes and try again\n");
                return EINVAL;
            }
            if (mixer_ctl_set_enum_by_string(ctl, values[0])) {
                fprintf(stderr, "Error: invalid enum value\n");
                return EINVAL;
            }
        } else {
            fprintf(stderr, "Error: only enum types can be set with strings\n");
            return EINVAL;
        }
    }

    return 0;
}

 

小结

        mixer和pcm一起构成了android 音频控制的底层架构TinyAlsa,对Android所有的音频控件而言,都需要通过JNI或者Audio HAL调到tinyalsa底层的mixer、pcm去进行音频device的初始以及配置问题。

        mixer里面有提供很多灵活的接口供linux底层,比如mixer_get_ctl、mixer_ctl_get_name、mixer_get_ctl_by_name、mixer_ctl_get_num_values等,相关的开发任务关键在于check API的熟悉度。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: mlp-mixer是一种全MLP架构,用于视觉任务。它使用多层感知机(MLP)来代替传统的卷积神经网络(CNN)来处理图像。这种架构的优点是可以更好地处理不同尺度和方向的特征,同时减少了计算和内存消耗。它在许多视觉任务中表现出色,例如图像分类、目标检测和语义分割。 ### 回答2: mlp-mixer是一种全连接多层感知器(Multi-Layer Perceptron,MLP)网络架构,用于视觉场景的图像分类任务。它是在自然语言处理领域中Transformer的启发下发展起来的。与CNN、ResNet等传统的卷积神经网络架构不同,mlp-mixer主要采用全连接层(FC)和MLP Block。 mlp-mixer架构设计的主要思想是将全局信息和本地信息分离,然后通过一系列由FC和MLP Block组成的混合层进行特征提取。在每个MLP Block中,特征向量会被分成多个部分进行局部特征提取,之后再全局汇聚。这样可以保证局部信息不会在多次卷积操作后丢失,并且全局信息的汇聚也是非常高效的。 另外,mlp-mixer架构中的Layer Norm和MLP Block中的GELU激活函数等技术也是有其特点的。Layer Norm是比Batch Norm更加具有一般性的归一化技术,可以提高模型对小批量数据的扩展性。而GELU激活函数在接近0处光滑,对精度保持了很好的提升。这些技术的运用让mlp-mixer模型具有了更好的稳定性和鲁棒性。 综上所述,mlp-mixer是一个全新的神经网络架构,其与传统的卷积神经网络的不同点在于摆脱了卷积操作,通过全连接层和MLP Block等模块提取图像特征。该模型有很强的泛化性,并且在图像分类任务上取得了不错的效果。它的优点在于良好的可扩展性和可解释性,且训练效果非常稳定。在未来,mlp-mixer模型或许有望在计算机视觉领域中取得更进一步的发展。 ### 回答3: MLP-Mixer是一种全MLP(多层感知器)的架构,可以应用于视觉任务中的图像分类和目标检测等任务。MLP-Mixer在CVPR 2021中被提出并于同年6月被公开发布。 传统的卷积神经网络(CNN)被广泛应用于计算机视觉领域。但是,随着计算机视觉任务的不断发展和增加,如何更好地处理不同类型和规模的数据集,成为了一个挑战。因此,MLP-Mixer尝试解决传统卷积神经网络中一些问题,例如参数共享、池化和批归一化等。 MLP-Mixer的主要思想是将传统的卷积操作替换为由若干密集连接层(全连接层)组成的mixing层。传统的卷积操作只考虑空间上的邻居关系,而mixing层考虑全局视角。mixing层通过对不同通道(channel)的信息进行交互,捕捉不同通道之间的全局相关性,提高了特征提取的效率和性能,同时降低卷积神经网络的复杂性。 此外,MLP-Mixer还引入了多层感知器池化层(MLP Pooling Layer)代替传统的最大池化层(Max Pooling Layer),使神经网络更加灵活和高效。MLP-Mixer考虑到了计算机视觉中不同尺度的特征信息,通过MLP池化层进行特征重组和降维,使得神经网络可以处理多尺度特征信息,提高特征提取的精度和速度。 总的来说,MLP-Mixer是一种全MLP的架构,其独特的mixing层和MLP Pooling层相比传统的卷积神经网络有着更好的性能和可扩展性。未来,MLP-Mixer有望在计算机视觉领域的各种任务中得到广泛的应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值