一、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;
}