使用Sox在C语言中播放音频文件无输出问题求助
使用Sox播放音频无输出的问题排查与修复
我目标是编写一个应用程序,用来查找、打开音频文件并通过Sox播放,但目前遇到了无法输出音频的问题。我参考并修改了一些示例代码,但仍然没有声音。我仅对原示例做了少量修改:从main函数创建实例并传递指针,在函数中指定实际的数据文件(测试时用了本地的示例文件,暂时没做文件搜索功能)。除非必要,我不想对输入文件添加任何效果处理。
以下是我当前的代码:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <assert.h> #include "sox.h" typedef struct State { sox_format_t *sox_in; sox_format_t *sox_out; sox_effects_chain_t *sox_chain; } State; State *sm; void init_player(sox_format_t* sxin, sox_format_t* sxout, sox_effects_chain_t* sxchain) { sm = (struct State*)malloc(sizeof(struct State)); sm->sox_in = sxin; sm->sox_out = sxout; sm->sox_chain = sxchain; } void play(State* s) { sm->sox_in = sox_open_read("/home/me/Music/sox_out1.flac", NULL, NULL, NULL); printf("successful read\n"); sm->sox_in = sox_open_write("default", &(sm->sox_in)->signal, NULL, "alsa", NULL, NULL); printf("successful write\n"); sm->sox_chain = sox_create_effects_chain(&(sm->sox_in)->encoding, &(sm->sox_out)->encoding); printf("chain created\n"); printf("starting to flow effects\n"); sox_flow_effects(sm->sox_chain, NULL, NULL); printf("successful flow\n"); sox_delete_effects_chain(sm->sox_chain); sox_close(sm->sox_out); sox_close(sm->sox_in); } int main() { static sox_format_t *in, *out; /* input and output files */ static sox_effects_chain_t *chain; assert(sox_init() == SOX_SUCCESS); init_player(in, out, chain); play(sm); }
问题点分析
- 输入指针被覆盖:
play函数中打开输入文件后,立刻用sox_open_write的结果覆盖了sm->sox_in,导致原输入文件指针丢失,根本无法读取音频数据。 - 缺少必要的效果节点:Sox的效果链必须包含输入、输出节点来完成数据流转,空的效果链无法传递音频数据到设备。
- 无错误检查:没有判断
sox_open_read、sox_open_write等关键函数的返回值,可能隐藏了文件不存在、设备无法打开等错误。 - 结构体逻辑混乱:
play函数传入了s参数却未使用,直接操作全局变量sm,逻辑冗余且易出问题。
修复后的代码
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <unistd.h> #include <assert.h> #include "sox.h" typedef struct State { sox_format_t *sox_in; sox_format_t *sox_out; sox_effects_chain_t *sox_chain; } State; // 初始化播放器实例 State* init_player(void) { State *sm = malloc(sizeof(State)); if (!sm) { perror("Failed to allocate State"); return NULL; } sm->sox_in = NULL; sm->sox_out = NULL; sm->sox_chain = NULL; return sm; } // 播放音频文件 int play(State* s, const char* audio_path) { if (!s) { fprintf(stderr, "Invalid State pointer\n"); return -1; } // 打开输入音频文件 s->sox_in = sox_open_read(audio_path, NULL, NULL, NULL); if (!s->sox_in) { fprintf(stderr, "Failed to open input file: %s\n", audio_path); return -1; } printf("Successfully opened input file\n"); // 打开ALSA输出设备 s->sox_out = sox_open_write("default", &s->sox_in->signal, NULL, "alsa", NULL, NULL); if (!s->sox_out) { fprintf(stderr, "Failed to open ALSA output device\n"); sox_close(s->sox_in); return -1; } printf("Successfully opened output device\n"); // 创建效果链 s->sox_chain = sox_create_effects_chain(&s->sox_in->encoding, &s->sox_out->encoding); if (!s->sox_chain) { fprintf(stderr, "Failed to create effects chain\n"); sox_close(s->sox_out); sox_close(s->sox_in); return -1; } printf("Effects chain created\n"); // 添加输入效果(从输入文件读取数据) sox_effect_t *eff = sox_create_effect(sox_find_effect("input")); char *args[] = {(char*)s->sox_in, NULL}; sox_effect_options(eff, 1, args); sox_add_effect(s->sox_chain, eff, &s->sox_in->signal, &s->sox_in->signal); free(eff); // 添加输出效果(写入到输出设备) eff = sox_create_effect(sox_find_effect("output")); args[0] = (char*)s->sox_out; sox_effect_options(eff, 1, args); sox_add_effect(s->sox_chain, eff, &s->sox_in->signal, &s->sox_out->signal); free(eff); // 流转音频数据 printf("Starting audio playback...\n"); int ret = sox_flow_effects(s->sox_chain, NULL, NULL); if (ret != SOX_SUCCESS) { fprintf(stderr, "Failed to flow effects\n"); } else { printf("Playback completed successfully\n"); } // 清理资源 sox_delete_effects_chain(s->sox_chain); sox_close(s->sox_out); sox_close(s->sox_in); return ret; } int main() { assert(sox_init() == SOX_SUCCESS); State* player = init_player(); if (!player) { sox_quit(); return EXIT_FAILURE; } play(player, "/home/me/Music/sox_out1.flac"); free(player); sox_quit(); // 清理Sox库资源 return EXIT_SUCCESS; }
关键修复说明
- 保留输入指针:分开存储输入文件和输出设备的指针,避免覆盖导致的数据源丢失。
- 添加核心效果节点:通过
input和output效果节点搭建数据流转通道,这是Sox播放音频的必要逻辑。 - 增加错误检查:对所有关键函数的返回值做判断,便于快速定位问题。
- 优化实例管理:去掉全局变量,改为通过函数返回实例指针,逻辑更清晰。
- 补充资源清理:在程序结束时调用
sox_quit(),正确释放Sox库占用的资源。
内容的提问来源于stack exchange,提问作者eh_whatever
相关产品推荐
相关产品推荐

