ALSA sequencer队列运行异常:snd_seq_queue_status_get_tick_time()始终返回0
解决ALSA队列
snd_seq_queue_status_get_tick_time()始终返回0的问题 我来帮你搞定这个问题——你的代码里创建并启动了队列,但tick_time一直返回0的核心原因是这个队列没有绑定有效的时钟源,也没有配置节拍器来驱动tick计数。ALSA的序列队列不会自动运行tick,必须手动配置时钟和节拍参数才行。
问题根源
ALSA的seq队列默认是“静止”的:
- 没有指定时钟源,队列不知道用什么来计时
- 没有设置节拍(tempo)和tick分辨率,队列没有递增tick的依据
- 单纯调用
snd_seq_start_queue只会让队列进入“就绪”状态,但没有实际的驱动源来推进tick
修复步骤
我们需要给队列添加三个关键配置:
- 绑定系统时钟作为队列的计时源
- 设置节拍(比如每分钟120拍)和每拍对应的tick数
- 优化代码,避免重复分配释放
queue_status结构(可选,但更高效)
修改后的完整代码
#include <stdio.h> #include <alsa/asoundlib.h> #include <unistd.h> // 确保sleep函数可用 int queue; snd_seq_t *seq_handle; snd_seq_tick_time_t current_tick; snd_seq_queue_status_t *status; snd_seq_queue_tempo_t *tempo; int main (int argc, char **argv) { int err; // 打开序列设备 if ((err = snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_INPUT | SND_SEQ_OPEN_OUTPUT, 0)) < 0) { fprintf(stderr, "无法打开序列设备: %s\n", snd_strerror(err)); return 1; } // 分配队列 queue = snd_seq_alloc_queue(seq_handle); if (queue < 0) { fprintf(stderr, "分配队列失败: %s\n", snd_strerror(queue)); snd_seq_close(seq_handle); return 1; } fprintf(stderr,"queue id=%d\n", queue); // 1. 设置队列时钟源为系统时钟 if ((err = snd_seq_set_queue_clock(seq_handle, queue, SND_SEQ_CLOCK_SYSTEM)) < 0) { fprintf(stderr, "设置队列时钟失败: %s\n", snd_strerror(err)); goto cleanup; } // 2. 分配并设置节拍参数:120BPM,每拍48个tick snd_seq_queue_tempo_malloc(&tempo); snd_seq_queue_tempo_set_tempo(tempo, 120, 48); // 参数:tempo结构体,BPM,每拍tick数 if ((err = snd_seq_set_queue_tempo(seq_handle, queue, tempo)) < 0) { fprintf(stderr, "设置队列节拍失败: %s\n", snd_strerror(err)); snd_seq_queue_tempo_free(tempo); goto cleanup; } snd_seq_queue_tempo_free(tempo); // 启动队列(此时队列会开始基于时钟和节拍递增tick) if ((err = snd_seq_start_queue(seq_handle, queue, NULL)) < 0) { fprintf(stderr, "启动队列失败: %s\n", snd_strerror(err)); goto cleanup; } // 预分配队列状态结构体,避免循环内重复分配释放 snd_seq_queue_status_malloc(&status); for(int i=0;i<4;i++) { // 获取队列状态 if ((err = snd_seq_get_queue_status(seq_handle, queue, status)) < 0) { fprintf(stderr, "获取队列状态失败: %s\n", snd_strerror(err)); break; } current_tick = snd_seq_queue_status_get_tick_time(status); fprintf(stderr,"tick=%lu\n", current_tick ); // 注意:tick_time是unsigned long类型,用%lu打印 sleep(1); } snd_seq_queue_status_free(status); cleanup: snd_seq_stop_queue(seq_handle, queue, NULL); snd_seq_free_queue(seq_handle, queue); snd_seq_close(seq_handle); return 0; }
关键修改点说明
- 绑定时钟源:
snd_seq_set_queue_clock指定用系统时钟驱动队列,确保队列有计时基准 - 设置节拍参数:
snd_seq_queue_tempo_set_tempo定义了每分钟节拍数(BPM)和每拍对应的tick数,这样队列就能根据时间计算出tick的递增速度 - 类型匹配:
snd_seq_tick_time_t是unsigned long类型,打印时要用%lu而不是%d,避免类型转换错误 - 资源优化:把
queue_status的分配移到循环外,减少内存分配开销 - 错误处理:添加了完整的错误检查,方便排查问题
现在运行修改后的代码,你应该能看到tick值随着时间递增了。
内容的提问来源于stack exchange,提问作者johnnyO




