commit 006cfa84a54c11fbc0f29ed4f089118e2b3f3ecb Author: cxh Date: Tue Jun 3 04:49:29 2025 +0000 initial commit diff --git a/001.wav b/001.wav new file mode 100644 index 0000000..e34a080 Binary files /dev/null and b/001.wav differ diff --git a/audio_play b/audio_play new file mode 100755 index 0000000..31e7fe8 Binary files /dev/null and b/audio_play differ diff --git a/audio_play.c b/audio_play.c new file mode 100644 index 0000000..289ebd1 --- /dev/null +++ b/audio_play.c @@ -0,0 +1,164 @@ +#include +#include +#include + +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; +} diff --git a/voice_guard b/voice_guard new file mode 100755 index 0000000..4075169 Binary files /dev/null and b/voice_guard differ diff --git a/voice_guard.c b/voice_guard.c new file mode 100644 index 0000000..bbdd108 --- /dev/null +++ b/voice_guard.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}