#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; }