1.安装pulseaudio
sudo apt-get install pulseaudio
sudo apt-get install libpulse-dev#开发包
sudo apt-get update
sudo apt-get install ffmpeg #ffmpeg
2.列出所有的音频输入源,其中包括麦克风 Name 即是pa_simple_new函数dev参数
pactl list sources
#结果
Source #0
State: RUNNING
Name: alsa_output.pci-0000_02_02.0.analog-stereo.monitor #录取系统声音的dev
Description: Monitor of Internal Audio Analog Stereo
Driver: module-alsa-card.c
...
Source #1
State: RUNNING
Name: alsa_input.pci-0000_02_02.0.analog-stereo
Description: Yeti Stereo Microphone Analog Stereo
Driver: module-alsa-card.c
...
1.发送方 测试代码
//pulse_simple_sender.cpp
#include <iostream>
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/pulseaudio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <vector>
#include <thread>
#include <mutex>
#define BUFSIZE 1400
#define PORT 12345
std::vector<std::string> vct_buff;
std::mutex g_mutex;
pa_source_info souceInfo[10];
int indexCount = 0;
bool isNullTerminated1(const char* str) {
while (*str != '\0') {
++str;
}
return (*str == '\0');
}
bool isNullTerminated(const char* str,int size) {
for (int i = 0; i < size; i++) {
if (str[i] != '\0') {
return false;
}
}
return true;
}
void process_audio_data(const void *input_data, size_t num_samples) {
const int16_t *samples = (const int16_t *)input_data;
for (size_t i = 0; i < num_samples; ++i) {
std::cout << "samples: " << samples[i] << std::endl;
}
}
//列出所有的音频输入源
void source_info_callback(pa_context* c, const pa_source_info* i, int eol, void* userdata) {
if (i) {
if(indexCount >= 10) return ;
int len = strlen(i->name);
souceInfo[indexCount].name = new char[len];
if(souceInfo[indexCount].name == NULL) return;
memcpy((void*)souceInfo[indexCount++].name,i->name,len);
}
}
//获取设备信息cmd 'pactl list sources'
int pactl_list_sources()
{
// 创建PulseAudio主循环
pa_mainloop* mainloop = pa_mainloop_new();
// 创建PulseAudio上下文
pa_mainloop_api* mainloop_api = pa_mainloop_get_api(mainloop);
pa_context* context = pa_context_new(mainloop_api, "PulseAudio Example");
// 连接到PulseAudio服务器
if (pa_context_connect(context, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) {
std::cerr << "Error: Unable to connect to PulseAudio server." << std::endl;
return EXIT_FAILURE;
}
// 等待连接成功
while (pa_context_get_state(context) != PA_CONTEXT_READY) {
pa_mainloop_iterate(mainloop, 1, nullptr);
}
// 请求音频源信息
pa_operation* op = pa_context_get_source_info_list(context, source_info_callback, nullptr);
// 等待回调完成
while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) {
pa_mainloop_iterate(mainloop, 1, nullptr);
}
// 释放资源
pa_operation_unref(op); // 等待操作完成后再释放
pa_context_disconnect(context);
pa_context_unref(context);
pa_mainloop_free(mainloop);
return EXIT_SUCCESS;
}
//mic声音
static void mic_read()
{
pa_simple *mic_stream = nullptr;
int error;
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 1
};
mic_stream = pa_simple_new(
nullptr,
"System Stream",
PA_STREAM_RECORD,
NULL,
"System Stream",
&ss,
nullptr,
nullptr,
&error
);
if (!mic_stream) {
std::cerr << "Could not create system stream: " << pa_strerror(error) << std::endl;
return ;
}
/*FILE *fp = fopen("mic.raw", "wb");
if (!fp) {
fprintf(stderr, "Failed to open output file\n");
return ;
}*/
while (true) {
// Read system audio data
char systemBuffer[BUFSIZE];
if (pa_simple_read(mic_stream, systemBuffer, sizeof(systemBuffer), &error) < 0) {
std::cerr << "Could not read system data: " << pa_strerror(error) << std::endl;
//fclose(fp);
pa_simple_free(mic_stream);
break;
}
//fwrite(systemBuffer, sizeof(char), sizeof(systemBuffer), fp);
std::string str(systemBuffer,sizeof(systemBuffer));
std::lock_guard<std::mutex> lockGuard(g_mutex);
vct_buff.push_back(str);
}
}
//读取系统声音
static void sys_read()
{
pa_simple *system_stream = nullptr;
int error;
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 1
};
std::cout << "sys monitor : " << souceInfo[0].name << std::endl;
system_stream = pa_simple_new(
nullptr,
"System Stream",
PA_STREAM_RECORD,
//"alsa_output.pci-0000_02_02.0.analog-stereo.monitor",
souceInfo[0].name,
"System Stream",
&ss,
nullptr,
nullptr,
&error
);
if (!system_stream) {
std::cerr << "Could not create system stream: " << pa_strerror(error) << std::endl;
return ;
}
FILE *fp = fopen("sys.raw", "wb");
if (!fp) {
fprintf(stderr, "Failed to open output file\n");
return ;
}
while (true) {
// Read system audio data
char systemBuffer[BUFSIZE];
if (pa_simple_read(system_stream, systemBuffer, sizeof(systemBuffer), &error) < 0) {
std::cerr << "Could not read system data: " << pa_strerror(error) << std::endl;
//fclose(fp);
pa_simple_free(system_stream);
break;
}
/*if(isNullTerminated(systemBuffer,BUFSIZE))
{
continue;
}*/
//process_audio_data(systemBuffer, sizeof(systemBuffer));
std::string str(systemBuffer,sizeof(systemBuffer));
//std::cout << "str.length() = " << str.length() << std::endl;
fwrite(systemBuffer, sizeof(char), sizeof(systemBuffer), fp);
// 写入文件
//fwrite((void *)str.c_str(), sizeof(char), str.length(), fp2);
std::lock_guard<std::mutex> lockGuard(g_mutex);
vct_buff.push_back(str);
}
}
int main() {
vct_buff.clear();
pactl_list_sources();//列出当前系统上可用的音频输入源
// 创建套接字
int clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (clientSocket == -1) {
std::cerr << "Error creating socket" << std::endl;
return -1;
}
// 设置服务器地址信息
sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
// 使用localhost作为服务器IP地址
inet_pton(AF_INET, "127.0.0.1", &serverAddress.sin_addr);
serverAddress.sin_port = htons(PORT);
std::thread t(sys_read); //读取系统声音
t.detach();
std::thread t_mic(mic_read); //mic声音
t_mic.detach();
//std::thread(mic_read,mic_stream).detach();
while (true) {
std::vector<std::string> tmp_vec;
tmp_vec.clear();
{
std::lock_guard<std::mutex> lockGuard(g_mutex);
if(vct_buff.empty()) continue;
tmp_vec = std::move(vct_buff);
}
for(auto str : tmp_vec)
{
const char *systemBuffer = str.c_str();
if(sendto(clientSocket, systemBuffer, BUFSIZE, 0, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0)
{
perror("Sendto failed");
break;
}
// else{
// std::cout << "sendto data success." << std::endl;
// }
usleep(10000);
}
}
for(int i=0;i<indexCount;i++)
{
if(souceInfo[0].name)
{
delete[] souceInfo[0].name;
}
}
return 0;
}
2.接收方 测试代码
//pulse_simple_receiver.cpp
#include <iostream>
#include <pulse/simple.h>
#include <pulse/error.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <vector>
#include <thread>
#include <mutex>
#define BUFSIZE 1400
#define PORT 12345
std::vector<std::string> vec_buff;
std::mutex g_playmutex;
static void play_back()
{
static const pa_sample_spec ss = {
.format = PA_SAMPLE_S16LE,
.rate = 44100,
.channels = 2
};
pa_simple *output_stream = nullptr;
int error;
output_stream = pa_simple_new(
nullptr,
"Output Stream",
PA_STREAM_PLAYBACK,
nullptr, // Use the default device for playback
"Output Stream",
&ss,
nullptr,
nullptr,
&error
);
if (!output_stream) {
std::cerr << "Could not create output stream: " << pa_strerror(error) << std::endl;
return ;
}
// 录制音频并写入文件
/*FILE *fp = fopen("output2.raw", "wb");
if (!fp) {
fprintf(stderr, "Failed to open output file\n");
return ;
}*/
while (true)
{
std::vector<std::string> tmp_vec;
tmp_vec.clear();
{
std::lock_guard<std::mutex> lockGuard(g_playmutex);
if(vec_buff.empty()) continue;
tmp_vec = std::move(vec_buff);
}
for(auto str : tmp_vec)
{
const char *systemBuffer = str.c_str();
//systemBuffer = str.c_str();
if (pa_simple_write(output_stream, systemBuffer, BUFSIZE, &error) < 0) {
std::cerr << "Could not write data to output stream: " << pa_strerror(error) << std::endl;
pa_simple_free(output_stream);
break;
}
// 写入文件
fwrite(systemBuffer, sizeof(char), BUFSIZE, fp);
}
}
if(fp)
{
fclose(fp);
}
return ;
}
int main() {
std::thread t(play_back);
t.detach();
// 创建套接字
int serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (serverSocket == -1) {
std::cerr << "Error creating socket" << std::endl;
return -1;
}
// 设置服务器地址信息
sockaddr_in serverAddress;
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = INADDR_ANY;
serverAddress.sin_port = htons(PORT);
// 绑定套接字到指定的地址和端口
if (bind(serverSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) {
std::cerr << "Error binding socket to address" << std::endl;
close(serverSocket);
return -1;
}
sockaddr_in clientAddress;
socklen_t clientAddressLength = sizeof(clientAddress);
char buffer[BUFSIZE];
// 录制音频并写入文件
/*FILE *fp1 = fopen("output1.raw", "wb");
if (!fp1) {
fprintf(stderr, "Failed to open output file\n");
return -1;
}*/
while (true) {
// Receive audio data from the client
ssize_t recv_size = recvfrom(serverSocket, buffer, sizeof(buffer), 0, (struct sockaddr*)&clientAddress, &clientAddressLength);
if (recv_size < 0) {
perror("Recvfrom failed");
break;
}
if(recv_size > 0)
{
//fwrite(buffer,sizeof(char),BUFSIZE,fp1);
std::cout << "receive stream success. " << recv_size << std::endl;
std::string str(buffer,sizeof(buffer));
std::lock_guard<std::mutex> lockGuard(g_playmutex);
vec_buff.push_back(str);
}
}
close(serverSocket);
// if(fp1)
// {
// fclose(fp1);
// }
return 0;
}
3.编译
g++ pulse_simple_sender.cpp -o pulse_simple_sender -lpulse-simple -lpulse -lpthread
./pulse_simple_sender
g++ pulse_simple_receiver.cpp -o pulse_simple_receiver -lpulse-simple -lpulse -lpthread
./pulse_simple_receiver
命令行实现录音
parec --format=s16le --rate=44100 --channels=1 --device=your-device | tee output.raw
ffmpeg -f s16le -ar 44100 -ac 1 -i output.raw output.mp3