pulseaudio如何加载侦听模块(module-loopback)


前言

pulseaudio是一款基于Linux系统的音频服务器,它基于ALSA层之上来实现音频相关的各种设备管理、音频处理等功能,为用户提供更好的音频服务,它的功能大多数已模块化的形式进行加载,今天我们主要讲解的功能是它的侦听功能


提示:以下是本篇文章正文内容,下面案例可供参考

一、侦听功能是什么?

所谓侦听,即边录音边边播放,这种应用场景大多用于客服人员等,用于客户沟通时,能够及时听到自己的发音状态并及时纠正

侦听在pulseaudio中的模块名称叫做(module-loopback)
源代码由 module-loopback.c 来实现

二、如何实现一个加载module-loopback的C程序

我们在外部可以基于pulseaudio以客户端的形式来加载模块功能函数,
例如,我们这里加载module-loopback模块,那么pulseaudio就会去源码中执行 module-loopback.c 并加载该模块,这一部分的pulseaudio源码不是我们的重点,我们这里知道如何加载就行,如下所示:

#include <pulse/simple.h>          // PulseAudio 简单 API 头文件
#include <pulse/context.h>         // PulseAudio 上下文 API 头文件
#include <pulse/error.h>           // PulseAudio 错误处理头文件
#include <pulse/mainloop.h>        // PulseAudio 主循环头文件
#include <pulse/introspect.h>      // PulseAudio 内省 API 头文件,用于查询内部状态
#include <stdio.h>                 // 标准输入输出头文件
#include <stdlib.h>                // 标准库,提供内存分配、字符串操作等功能

// 设备名称常量,用于指定具体的输入和输出设备
const char *source_name_a = "alsa_input.usb-HECATE_G2_GAMING_HEADSET_HECATE_G2_GAMING_HEADSET_20190403-00.mono-fallback";
const char *sink_name_a = "alsa_output.usb-HECATE_G2_GAMING_HEADSET_HECATE_G2_GAMING_HEADSET_20190403-00.analog-stereo";

// 函数:加载 loopback 模块
int load_loopback(pa_context *context)
{
    pa_operation *o = NULL; // 创建操作句柄
    char *args = NULL;
    //需要将输入输出设备名合成为一个参数传递给pulseaudio
    asprintf(&args, "source=%s sink=%s", source_name_a, sink_name_a);

    //通过pulseaudio的api函数加载loopback 模块,参数为上下文、模块名、参数字符串、完成回调和回调数据
    o = pa_context_load_module(context, "module-loopback", args, NULL, NULL);
    free(args);
    if (!o) {
        fprintf(stderr, "Failed to load module-loopback\n");
        return -1;
    }
    return 0;
}

//状态回调函数,监听上下文状态变化
static void state_cb(pa_context *c, void *userdata) {

    // 获取当前上下文状态
    const pa_context_state_t state = pa_context_get_state(c);

    // 根据状态执行不同操作
    switch(state) {
        case PA_CONTEXT_UNCONNECTED:    // 未连接状态
        case PA_CONTEXT_CONNECTING:     // 正在连接状态
        case PA_CONTEXT_AUTHORIZING:    // 授权状态
        case PA_CONTEXT_SETTING_NAME:   // 设置名称状态
            break;
        //当client连接状态为ready时,才能正常加载模块
        case PA_CONTEXT_READY:          // 准备就绪状态
            printf("Context is ready.\n");
            load_loopback(c);
            break;
        case PA_CONTEXT_FAILED:         // 连接失败状态
            fprintf(stderr, "state_cb: connect failed.\n");
            break;
        case PA_CONTEXT_TERMINATED:     // 终止状态
            break;
    }
}

int main() {

    pa_context *context = NULL;     // PulseAudio 上下文句柄
    pa_mainloop *mainloop = NULL;   // 主循环句柄
    pa_operation *o = NULL;         // 操作句柄

    // 创建主循环
    mainloop = pa_mainloop_new();
    if (!mainloop) {
        fprintf(stderr, "Failed to create main loop\n");
        return 1;
    }
    // 创建上下文,参数为主循环 API、应用程序名称
    context = pa_context_new(pa_mainloop_get_api(mainloop), "LoopbackExample");
    if (!context) {
        fprintf(stderr, "Failed to create context\n");
        goto error;
    }
    // 连接上下文,参数为 NULL 表示使用默认服务器、连接标志为 0、无特殊参数
    if (pa_context_connect(context, NULL, 0, NULL) < 0) {
        fprintf(stderr, "Failed to connect context\n");
        goto error;
    }
    // 设置状态回调函数,参数为上下文、回调函数、回调数据
    pa_context_set_state_callback(context, (pa_context_notify_cb_t)state_cb, NULL);

    // 运行主循环
    pa_mainloop_run(mainloop, NULL);

error:
    // 清理资源,包括操作句柄、上下文、主循环
    if (o) {
        pa_operation_unref(o);
    }

    if (context) {
        pa_context_disconnect(context);
        pa_context_unref(context);
    }

    if (mainloop) {
        pa_mainloop_free(mainloop);
    }

    return o ? 0 : 1; // 如果操作成功,则返回0,否则返回1
}

三、注意事项

1、必须装有 libpulsedev 包

dpkg -l |grep libpulse-dev

在这里插入图片描述
如果没有,则需要安装

sudo apt install libpulse-dev

2、编译方式

gcc -D_GNU_SOURCE pa_load_loopback_org.c -lpulse

3、运行说明

运行此代码时,需要注意pulseaudio必须在运行,因为我们这个实例是基于pulseaudio来加载模块的

此代码中固定了设备,后期可以自行更换设备端口进行验证

4、查看模块是否加载成功

一般情况下,运行成功后,可以从代码中指定的输入输出设备听出来的

如果不放心,可以使用这条命令查看

pactl list modules short

这里会列出pulseaudio所加载的所有模块,这个排序是按照时间顺序来的,可以看到我们刚刚运行代码后,现在已经成功加载了
module-loopback
在这里插入图片描述

5、卸载模块

代码中我们并没有实现如何卸载模块,这个需要手动输入命令实现

pactl unload-module module-loopback
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值