initial commit
This commit is contained in:
commit
006cfa84a5
BIN
audio_play
Executable file
BIN
audio_play
Executable file
Binary file not shown.
164
audio_play.c
Normal file
164
audio_play.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
|
void check_and_set_max_volume()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buffer[256];
|
||||||
|
int volume_left = -1;
|
||||||
|
int speaker_on = 0;
|
||||||
|
|
||||||
|
// 检查 PCM 音量
|
||||||
|
fp = popen("amixer get PCM | grep 'Front Left'", "r");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
while (fgets(buffer, sizeof(buffer), fp))
|
||||||
|
{
|
||||||
|
if (sscanf(buffer, " Front Left: %d", &volume_left) == 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (volume_left == -1)
|
||||||
|
{
|
||||||
|
printf("无法获取音量信息\n");
|
||||||
|
}
|
||||||
|
else if (volume_left < 192)
|
||||||
|
{
|
||||||
|
printf("当前音量为 %d,设置为最大...\n", volume_left);
|
||||||
|
system("amixer set PCM 192");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("音量已是最大(%d)\n", volume_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查扬声器是否开启
|
||||||
|
fp = popen("amixer get Speaker | grep 'Mono:'", "r");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
while (fgets(buffer, sizeof(buffer), fp))
|
||||||
|
{
|
||||||
|
if (strstr(buffer, "[on]"))
|
||||||
|
{
|
||||||
|
speaker_on = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!speaker_on)
|
||||||
|
{
|
||||||
|
printf("扬声器未打开,正在开启...\n");
|
||||||
|
system("amixer set Speaker unmute");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("扬声器已开启\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
check_and_set_max_volume();
|
||||||
|
|
||||||
|
const char *device = "hw:0,0"; // 要使用的 ALSA 设备
|
||||||
|
const char *filename = "001.wav"; // WAV 文件路径
|
||||||
|
snd_pcm_t *pcm_handle;
|
||||||
|
snd_pcm_hw_params_t *params;
|
||||||
|
unsigned int sample_rate = 44100; // 采样率(需与 WAV 文件一致)
|
||||||
|
int pcm, dir;
|
||||||
|
snd_pcm_uframes_t frames;
|
||||||
|
FILE *file;
|
||||||
|
char *buffer;
|
||||||
|
int buffer_size;
|
||||||
|
|
||||||
|
// 打开音频文件
|
||||||
|
file = fopen(filename, "rb");
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
perror("Unable to open audio file");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳过标准 WAV 头部(44 字节),如果你的音频文件已经是纯 PCM 数据可以注释掉此行
|
||||||
|
fseek(file, 44, SEEK_SET);
|
||||||
|
|
||||||
|
// 打开 PCM 设备
|
||||||
|
if ((pcm = snd_pcm_open(&pcm_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to open PCM device %s: %s\n", device, snd_strerror(pcm));
|
||||||
|
fclose(file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分配并初始化硬件参数对象
|
||||||
|
snd_pcm_hw_params_alloca(¶ms);
|
||||||
|
snd_pcm_hw_params_any(pcm_handle, params);
|
||||||
|
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
|
snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE);
|
||||||
|
snd_pcm_hw_params_set_channels(pcm_handle, params, 2);
|
||||||
|
snd_pcm_hw_params_set_rate_near(pcm_handle, params, &sample_rate, &dir);
|
||||||
|
|
||||||
|
// 应用硬件参数
|
||||||
|
if ((pcm = snd_pcm_hw_params(pcm_handle, params)) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to set hardware parameters: %s\n", snd_strerror(pcm));
|
||||||
|
snd_pcm_close(pcm_handle);
|
||||||
|
fclose(file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取每个周期(period)的帧数,并据此计算缓冲区大小
|
||||||
|
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
|
||||||
|
buffer_size = frames * 2 /*bytes per sample*/ * 2 /*channels*/;
|
||||||
|
buffer = (char *)malloc(buffer_size);
|
||||||
|
if (!buffer)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unable to allocate buffer\n");
|
||||||
|
snd_pcm_close(pcm_handle);
|
||||||
|
fclose(file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无限循环播放
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
size_t bytes_read = fread(buffer, 1, buffer_size, file);
|
||||||
|
if (bytes_read == 0)
|
||||||
|
{
|
||||||
|
// 已经读到文件末尾,重新回到数据区的起始位置(跳过头部)
|
||||||
|
fseek(file, 44, SEEK_SET);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算本次要写入的“帧”数,如果最后一块数据不足一个完整周期,按实际读到的字节数计算
|
||||||
|
snd_pcm_uframes_t frames_to_deliver = bytes_read / (2 * 2);
|
||||||
|
|
||||||
|
// 写入 PCM
|
||||||
|
int ret = snd_pcm_writei(pcm_handle, buffer, frames_to_deliver);
|
||||||
|
if (ret == -EPIPE)
|
||||||
|
{
|
||||||
|
// 缓冲区下溢,重启 PCM 设备
|
||||||
|
snd_pcm_prepare(pcm_handle);
|
||||||
|
}
|
||||||
|
else if (ret < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Playback error: %s\n", snd_strerror(ret));
|
||||||
|
}
|
||||||
|
// 如果写入的帧数小于需要的,可以在这里处理(可选)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下面的代码理论上永远不会执行到,但为了完整性保留
|
||||||
|
free(buffer);
|
||||||
|
snd_pcm_drain(pcm_handle);
|
||||||
|
snd_pcm_close(pcm_handle);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
voice_guard
Executable file
BIN
voice_guard
Executable file
Binary file not shown.
163
voice_guard.c
Normal file
163
voice_guard.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#define PORT 9999
|
||||||
|
#define TIMEOUT 3
|
||||||
|
|
||||||
|
pid_t play_pid = 0;
|
||||||
|
|
||||||
|
// 启动播放
|
||||||
|
void start_playback()
|
||||||
|
{
|
||||||
|
if (play_pid == 0)
|
||||||
|
{
|
||||||
|
play_pid = fork();
|
||||||
|
if (play_pid == 0)
|
||||||
|
{
|
||||||
|
execl("./audio_play", "./audio_play", NULL);
|
||||||
|
perror("execl failed");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("播放进程已启动,PID=%d\n", play_pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止播放
|
||||||
|
void stop_playback()
|
||||||
|
{
|
||||||
|
if (play_pid > 0)
|
||||||
|
{
|
||||||
|
printf("停止播放,终止 PID=%d\n", play_pid);
|
||||||
|
kill(play_pid, SIGTERM);
|
||||||
|
waitpid(play_pid, NULL, 0);
|
||||||
|
play_pid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int listen_fd, conn_fd;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
char buffer[128];
|
||||||
|
time_t last_time = 0;
|
||||||
|
int playing = 0;
|
||||||
|
fd_set read_fds;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (listen_fd < 0)
|
||||||
|
{
|
||||||
|
perror("socket error");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int opt = 1;
|
||||||
|
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(PORT);
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
|
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
||||||
|
{
|
||||||
|
perror("bind error");
|
||||||
|
close(listen_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(listen_fd, 5) < 0)
|
||||||
|
{
|
||||||
|
perror("listen error");
|
||||||
|
close(listen_fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("语音守护 TCP 服务器已启动,监听端口 %d...\n", PORT);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
printf("等待客户端连接...\n");
|
||||||
|
conn_fd = accept(listen_fd, NULL, NULL);
|
||||||
|
if (conn_fd < 0)
|
||||||
|
{
|
||||||
|
perror("accept error");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
printf("客户端已连接\n");
|
||||||
|
|
||||||
|
last_time = 0;
|
||||||
|
playing = 0;
|
||||||
|
|
||||||
|
// 设置非阻塞模式
|
||||||
|
fcntl(conn_fd, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
FD_SET(conn_fd, &read_fds);
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
int ret = select(conn_fd + 1, &read_fds, NULL, NULL, &tv);
|
||||||
|
if (ret > 0 && FD_ISSET(conn_fd, &read_fds))
|
||||||
|
{
|
||||||
|
ssize_t len = read(conn_fd, buffer, sizeof(buffer) - 1);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
buffer[len] = '\0';
|
||||||
|
if (strstr(buffer, "RUNNING"))
|
||||||
|
{
|
||||||
|
last_time = time(NULL);
|
||||||
|
if (!playing)
|
||||||
|
{
|
||||||
|
printf("收到心跳,启动播报...\n");
|
||||||
|
start_playback();
|
||||||
|
playing = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (len == 0)
|
||||||
|
{
|
||||||
|
printf("客户端关闭连接\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
{
|
||||||
|
// 超时
|
||||||
|
if (playing && (time(NULL) - last_time > TIMEOUT))
|
||||||
|
{
|
||||||
|
printf("超时未收到心跳,停止播报...\n");
|
||||||
|
stop_playback();
|
||||||
|
playing = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perror("select error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(conn_fd);
|
||||||
|
// 断开连接时停止播放
|
||||||
|
if (playing)
|
||||||
|
{
|
||||||
|
printf("连接断开,停止播放\n");
|
||||||
|
stop_playback();
|
||||||
|
playing = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(listen_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user