linux下使用PulseAudio获取扬声器的音量和是否静音

本文档介绍PulseAudio中的sourcedevice和sinkdevice概念,分别代表声音来源和接收端。并展示了如何用C++通过PulseAudio库获取sinkdevice的音量和静音状态。示例代码包括连接PulseAudio上下文、获取设备信息及断开连接的函数,以及回调函数用于处理设备信息和上下文状态。
摘要由CSDN通过智能技术生成

一、source device和sink device的概念

source device:source可以理解为源泉,表示声音的源,即声音产生的地方

sink device:sink可以理解为水槽,表示声音的接受一方

那么就可以理解为声音从source device流出,流到sink device里面
二、获取sink device的音量和是不是静音

#include <iostream>
#include <memory>
#include <vector>
#include <string>
 
#include <pulse/error.h>
#include <pulse/pulseaudio.h>
#include <pulse/simple.h>
 
enum class PulseAudioContextState {
    PULSE_CONTEXT_INITIALIZING,
    PULSE_CONTEXT_READY,
    PULSE_CONTEXT_FINISHED
};
 
struct SinkInfo {
    pa_cvolume volume;  //音量
    int mute;           //是不是静音,1表示静音,0表示非静音
};
 
void DisconnectPulseAudioContext(pa_mainloop** pa_ml, pa_context** pa_ctx) {
    assert(pa_ml);
    assert(pa_ctx);
 
    if (*pa_ctx) {
        pa_context_set_state_callback(*pa_ctx, NULL, NULL);
        pa_context_disconnect(*pa_ctx);
        pa_context_unref(*pa_ctx);
    }
 
    if (*pa_ml) pa_mainloop_free(*pa_ml);
    *pa_ml = NULL;
    *pa_ctx = NULL;
}
 
void PaContextStateCallback(pa_context* pa_ctx, void* userdata) {
    PulseAudioContextState* context_state = (PulseAudioContextState*)userdata;
    switch (pa_context_get_state(pa_ctx)) {
        case PA_CONTEXT_FAILED:
        case PA_CONTEXT_TERMINATED:
            *context_state = PulseAudioContextState::PULSE_CONTEXT_FINISHED;
            break;
        case PA_CONTEXT_READY:
            *context_state = PulseAudioContextState::PULSE_CONTEXT_READY;
            break;
        default:
            break;
    }
}
 
int ConnectPulseAudioContext(pa_mainloop** pa_ml, pa_context** pa_ctx,
                             const char* server, const char* description) {
    int ret;
    *pa_ml = NULL;
    *pa_ml = pa_mainloop_new();
    if (!(*pa_ml)) { return -1; }
 
    pa_mainloop_api* pa_mlapi = NULL;
    pa_mlapi = pa_mainloop_get_api(*pa_ml);
    if (!pa_mlapi) { return -1; }
 
    *pa_ctx = NULL;
    *pa_ctx = pa_context_new(pa_mlapi, description);
    if (!(*pa_ctx)) { return -1; }
 
    PulseAudioContextState context_state =
            PulseAudioContextState::PULSE_CONTEXT_INITIALIZING;
    pa_context_set_state_callback(*pa_ctx, PaContextStateCallback,
                                  &context_state);
    if (pa_context_connect(*pa_ctx, server, PA_CONTEXT_NOFLAGS, NULL) < 0) {
        return -1;
    }
 
    while (context_state == PulseAudioContextState::PULSE_CONTEXT_INITIALIZING)
        pa_mainloop_iterate(*pa_ml, 1, NULL);
    if (context_state == PulseAudioContextState::PULSE_CONTEXT_FINISHED) {
        return -1;
    }
    return 0;
}
 
void PulseAudioSinkDeviceInfoCallback(pa_context* c, const pa_sink_info* info,
                                      int eol, void* userdata) {
    SinkInfo* sink_info = (SinkInfo*)userdata;
    if (info != nullptr) {
        sink_info->volume = info->volume;
        sink_info->mute = info->mute;
        for (int i = 0; i < info->volume.channels; ++i) {
            // 打印各个声道的音量
            std::cout << (info->volume.values[i]*1.0 / info->base_volume)*100 << std::endl;
        }
        std::cout << "mute:" << info->mute << std::endl;
    }
}
 
SinkInfo GetPulseAudioSinkDeviceInfo(const std::string& sink_device) {
    SinkInfo sink_info;
    pa_mainloop* pa_ml = nullptr;
    pa_operation* pa_op = nullptr;
    pa_context* pa_ctx = nullptr;
    ConnectPulseAudioContext(&pa_ml, &pa_ctx, nullptr, "audio recorder");
    std::shared_ptr<void> raii_connect(nullptr, [&](void*) {
        DisconnectPulseAudioContext(&pa_ml, &pa_ctx);
    });
    if (pa_ctx == nullptr) { return sink_info; }
    pa_op = pa_context_get_sink_info_by_name(pa_ctx, sink_device.c_str(),
                                             PulseAudioSinkDeviceInfoCallback,
                                             &sink_info);
    while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
        pa_mainloop_iterate(pa_ml, 1, nullptr);
    }
    pa_operation_unref(pa_op);
    return sink_info;
}
 
void PulseAudioSinkDeviceCallback(pa_context* c, const pa_sink_info* dev,
                                  int eol, void* userdata) {
    std::vector<std::string>* devices = (std::vector<std::string>*)userdata;
    if (dev != nullptr) { devices->push_back(dev->name); }
}
 
std::vector<std::string> GetPulseAudioSinkDevice() {
    std::vector<std::string> sink_devices_vec;
    pa_mainloop* pa_ml = nullptr;
    pa_operation* pa_op = nullptr;
    pa_context* pa_ctx = nullptr;
    ConnectPulseAudioContext(&pa_ml, &pa_ctx, nullptr, "audio recorder");
    std::shared_ptr<void> raii_connect(nullptr, [&](void*) {
        DisconnectPulseAudioContext(&pa_ml, &pa_ctx);
    });
    if (pa_ctx == nullptr) { return sink_devices_vec; }
    pa_op = pa_context_get_sink_info_list(pa_ctx, PulseAudioSinkDeviceCallback,
                                          &sink_devices_vec);
    while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) {
        pa_mainloop_iterate(pa_ml, 1, nullptr);
    }
    pa_operation_unref(pa_op);
    return sink_devices_vec;
}
 
int main(void) {
    std::vector<std::string> sink_devices_vec = GetPulseAudioSinkDevice();
    SinkInfo sink_info = GetPulseAudioSinkDeviceInfo(sink_devices_vec[0]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值