导致嵌入式Linux上有1秒钟的延迟,并具有ALSA支持和简单的C++程序?
我正在尝试开发一个在ADSL路由器上运行的简单音频程序。我找到了两个具有相同芯片的路由器的GPL来源,并且能够构建内核和rootfs。我已经在内核中添加了ALSA支持,并成功部署到路由器。
现在,我试图让我的程序上班。使用USB声卡,我要做的第一件事是将捕获信号传递给播放并测量延迟。
我已经删除了所有存在的抖动,但是我无法获得比1秒的更好的延迟(这是很多延迟)。我正在用128帧的缓冲区和1帧初始化设备,而延迟始终为1秒。我仅使用1个频道,速率为44100,但也以8000Hz的速率进行了测试,而潜伏期是相同的
我已经尝试设置跑步线程的另一个优先级,并测试了很多组合HW参数,但永远不会延迟延迟。
我的程序运行时检查了CPU和内存,并且有很多免费资源。我删除了系统的许多服务,例如Telnet,Samba和其他可能干扰我程序的程序。
一个有趣的观点是,当我的程序仅设置播放设备并播放一些PCM文件时,没有延迟(在我启动程序后,声音就可以正确播放)。
Linux内核版本为v2.6.22.15。 ALSA驱动程序为1.0.14。我尝试了一张便宜的USB声卡,缩放H1录音机(可作为USB卡)和Presonus 22VSL音频接口,总是相同的延迟。
CPU是Ralink RT63365,它具有4个内核,似乎以400Hz APROX运行。
我不知道还要尝试什么。我可以做什么样的测试来检测延迟问题的产生位置?
编辑
我忘记提到我在PC(内核版本> 5,具有相应的ALSA版本)中运行了相同的程序,并且该程序完美地工作,没有显着的潜伏期。
我程序的主要功能:
void setscheduler(void)
{
struct sched_param sched_param;
if (sched_getparam(0, &sched_param) < 0) {
printf("Scheduler getparam failed...\n");
return;
}
sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
printf("Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority);
fflush(stdout);
return;
}
printf("!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority);
}
int setup_alsa_handle(snd_pcm_t *handle, snd_pcm_stream_t stream)
{
int err = 0;
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0)
{
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_set_access(handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_set_format(handle, hw_params, AUDIO_FORMAT)) < 0)
{
fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(err));
exit(1);
}
unsigned int rate = SAMPLE_RATE;
if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0)) <
0)
{
fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(err));
exit(1);
}
int dir;
snd_pcm_uframes_t period_size = PERIOD_SIZE_IN_FRAMES;
if ((err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, &dir)) <
0)
{
fprintf(stderr, "cannot set period size (%s)\n", snd_strerror(err));
exit(1);
}
int channels;
if (stream == SND_PCM_STREAM_CAPTURE)
{
channels = CAPTURE_CHANNELS;
}
else
{
channels = PLAYBACK_CHANNELS;
}
if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0)
{
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params(handle, hw_params)) < 0)
{
fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err));
exit(1);
}
snd_pcm_hw_params_free(hw_params);
if ((err = snd_pcm_sw_params_malloc(&sw_params)) < 0) {
fprintf(stderr, "cannot allocate software parameters structure(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_current(handle, sw_params)) < 0) {
fprintf(stderr, "cannot initialize software parameters structure(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_set_avail_min(handle, sw_params, FRAMES_PER_BUFFER)) < 0) {
fprintf(stderr, "cannot set minimum available count(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, 0U)) < 0) {
fprintf(stderr, "cannot set start mode(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params(handle, sw_params)) < 0) {
fprintf(stderr, "cannot set software parameters(%s)\n",
snd_strerror(err));
return err;
}
return 0;
}
void start_stream(snd_pcm_t *_playback_handle, snd_pcm_t *_capture_handle,
void (*stream_callback)(const void *, void *, unsigned long,
void *),
void (*controls_callback)(void *), void *data)
{
audio_sample *in_buffer;
audio_sample *out_buffer;
FILE *fout = NULL;
int in_result = 0;
int out_result = 0;
int temp_n = 0;
int buffer_frames = FRAMES_PER_BUFFER;
int frame_size_in_bytes = snd_pcm_format_width(AUDIO_FORMAT) / 8;
int in_buffer_frames = buffer_frames * CAPTURE_CHANNELS;
in_buffer = (audio_sample *)malloc(in_buffer_frames * frame_size_in_bytes);
int out_buffer_frames = buffer_frames * PLAYBACK_CHANNELS;
out_buffer = (audio_sample *)malloc(out_buffer_frames * frame_size_in_bytes);
memset(in_buffer, SAMPLE_SILENCE, in_buffer_frames * frame_size_in_bytes);
memset(out_buffer, SAMPLE_SILENCE, out_buffer_frames * frame_size_in_bytes);
int err;
while (1)
{
int avail;
if ((err = snd_pcm_wait(_playback_handle, 1000)) < 0) {
fprintf(stderr, "poll failed(%s)\n", strerror(errno));
break;
}
avail = snd_pcm_avail_update(_capture_handle);
fprintf(stderr, "1 avail (%d)\n", avail);
if (avail > 0) {
if (avail > FRAMES_PER_BUFFER)
avail = FRAMES_PER_BUFFER;
snd_pcm_readi(_capture_handle, in_buffer, avail);
}
avail = snd_pcm_avail_update(_playback_handle);
fprintf(stderr, "2 avail (%d)\n", avail);
if (avail > 0) {
if (avail > FRAMES_PER_BUFFER)
avail = FRAMES_PER_BUFFER;
snd_pcm_writei(_playback_handle, in_buffer, avail);
}
}
}
/**
* Main
*/
int main(int argc, char *argv[])
{
setscheduler();
if ((err = snd_pcm_open(&capture_handle, CAPTURE_AUDIO_DEVICE, SND_PCM_STREAM_CAPTURE, 0)) < 0)
{
fprintf(stderr, "cannot open audio device '%s'. Error: %s\n", CAPTURE_AUDIO_DEVICE, snd_strerror(err));
exit(1);
}
setup_alsa_handle(capture_handle, SND_PCM_STREAM_CAPTURE);
// Init playback device
if ((err = snd_pcm_open(&playback_handle, PLAYBACK_AUDIO_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf(stderr, "cannot open audio device '%s'. Error: %s\n", PLAYBACK_AUDIO_DEVICE, snd_strerror(err));
exit(1);
}
setup_alsa_handle(playback_handle, SND_PCM_STREAM_PLAYBACK);
if ((err = snd_pcm_start(capture_handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_prepare(playback_handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
snd_strerror(err));
return err;
}
// Start stream
start_stream(playback_handle, capture_handle, audio_processing_callback, controls_callback, &data, write_to_file, read_from_file);
return 0;
}
I'm trying to develop a simple audio program that runs on a ADSL router. I found two GPL sources for other routers that have the same chips and I'm able to build kernel and rootfs. I already add ALSA support to the kernel and successfully deployed to the router.
Now I'm trying to get my program to work. Using a usb sound card, the first thing that I'm doing is to passthrough capture signal to the playback and measure the latency.
I already remove all jitter that was present but I can't get a better latency that 1 second (it's a lot of latency). I'm initializing the device with 128 frames of buffer and 1 frame for period size, and latency is always 1 second. I'm using only 1 channel and a rate of 44100, but also tested with a rate of 8000hz and the latency is the same
I already tried setting another priority to the running thread and tested a lot of combinations of hw params, but never could get minor latency than that.
I checked the cpu and memory while my program is running and there is a lot of free resources. I removed many services of the system like telnet, samba and other programs that could interfere with my program.
An interesting point is that when my program only set the playback device and play some pcm file, there is no latency (right after I start the program, the sound is played correctly).
Linux kernel version is v2.6.22.15. Alsa driver is 1.0.14. I tried a cheap usb sound card, a Zoom h1 recorder (that works as usb card) and a Presonus 22vsl audio interface, always the same latency.
The CPU is a Ralink rt63365, it has 4 cores and it seems to run at 400hz aprox.
I don't know what else to try. What kind of test could I do to detect where the latency problem is generated?
Edit
I forget to mention that I run the same program with all the cards mentioned but in my PC (kernel version > 5, with the respective alsa version) and the program works perfectly, there is no notable latency.
Main functions of my program:
void setscheduler(void)
{
struct sched_param sched_param;
if (sched_getparam(0, &sched_param) < 0) {
printf("Scheduler getparam failed...\n");
return;
}
sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
printf("Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority);
fflush(stdout);
return;
}
printf("!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority);
}
int setup_alsa_handle(snd_pcm_t *handle, snd_pcm_stream_t stream)
{
int err = 0;
snd_pcm_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params;
if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_any(handle, hw_params)) < 0)
{
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n",
snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_set_access(handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params_set_format(handle, hw_params, AUDIO_FORMAT)) < 0)
{
fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(err));
exit(1);
}
unsigned int rate = SAMPLE_RATE;
if ((err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rate, 0)) <
0)
{
fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(err));
exit(1);
}
int dir;
snd_pcm_uframes_t period_size = PERIOD_SIZE_IN_FRAMES;
if ((err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &period_size, &dir)) <
0)
{
fprintf(stderr, "cannot set period size (%s)\n", snd_strerror(err));
exit(1);
}
int channels;
if (stream == SND_PCM_STREAM_CAPTURE)
{
channels = CAPTURE_CHANNELS;
}
else
{
channels = PLAYBACK_CHANNELS;
}
if ((err = snd_pcm_hw_params_set_channels(handle, hw_params, channels)) < 0)
{
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err));
exit(1);
}
if ((err = snd_pcm_hw_params(handle, hw_params)) < 0)
{
fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err));
exit(1);
}
snd_pcm_hw_params_free(hw_params);
if ((err = snd_pcm_sw_params_malloc(&sw_params)) < 0) {
fprintf(stderr, "cannot allocate software parameters structure(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_current(handle, sw_params)) < 0) {
fprintf(stderr, "cannot initialize software parameters structure(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_set_avail_min(handle, sw_params, FRAMES_PER_BUFFER)) < 0) {
fprintf(stderr, "cannot set minimum available count(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, 0U)) < 0) {
fprintf(stderr, "cannot set start mode(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_sw_params(handle, sw_params)) < 0) {
fprintf(stderr, "cannot set software parameters(%s)\n",
snd_strerror(err));
return err;
}
return 0;
}
void start_stream(snd_pcm_t *_playback_handle, snd_pcm_t *_capture_handle,
void (*stream_callback)(const void *, void *, unsigned long,
void *),
void (*controls_callback)(void *), void *data)
{
audio_sample *in_buffer;
audio_sample *out_buffer;
FILE *fout = NULL;
int in_result = 0;
int out_result = 0;
int temp_n = 0;
int buffer_frames = FRAMES_PER_BUFFER;
int frame_size_in_bytes = snd_pcm_format_width(AUDIO_FORMAT) / 8;
int in_buffer_frames = buffer_frames * CAPTURE_CHANNELS;
in_buffer = (audio_sample *)malloc(in_buffer_frames * frame_size_in_bytes);
int out_buffer_frames = buffer_frames * PLAYBACK_CHANNELS;
out_buffer = (audio_sample *)malloc(out_buffer_frames * frame_size_in_bytes);
memset(in_buffer, SAMPLE_SILENCE, in_buffer_frames * frame_size_in_bytes);
memset(out_buffer, SAMPLE_SILENCE, out_buffer_frames * frame_size_in_bytes);
int err;
while (1)
{
int avail;
if ((err = snd_pcm_wait(_playback_handle, 1000)) < 0) {
fprintf(stderr, "poll failed(%s)\n", strerror(errno));
break;
}
avail = snd_pcm_avail_update(_capture_handle);
fprintf(stderr, "1 avail (%d)\n", avail);
if (avail > 0) {
if (avail > FRAMES_PER_BUFFER)
avail = FRAMES_PER_BUFFER;
snd_pcm_readi(_capture_handle, in_buffer, avail);
}
avail = snd_pcm_avail_update(_playback_handle);
fprintf(stderr, "2 avail (%d)\n", avail);
if (avail > 0) {
if (avail > FRAMES_PER_BUFFER)
avail = FRAMES_PER_BUFFER;
snd_pcm_writei(_playback_handle, in_buffer, avail);
}
}
}
/**
* Main
*/
int main(int argc, char *argv[])
{
setscheduler();
if ((err = snd_pcm_open(&capture_handle, CAPTURE_AUDIO_DEVICE, SND_PCM_STREAM_CAPTURE, 0)) < 0)
{
fprintf(stderr, "cannot open audio device '%s'. Error: %s\n", CAPTURE_AUDIO_DEVICE, snd_strerror(err));
exit(1);
}
setup_alsa_handle(capture_handle, SND_PCM_STREAM_CAPTURE);
// Init playback device
if ((err = snd_pcm_open(&playback_handle, PLAYBACK_AUDIO_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
fprintf(stderr, "cannot open audio device '%s'. Error: %s\n", PLAYBACK_AUDIO_DEVICE, snd_strerror(err));
exit(1);
}
setup_alsa_handle(playback_handle, SND_PCM_STREAM_PLAYBACK);
if ((err = snd_pcm_start(capture_handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
snd_strerror(err));
return err;
}
if ((err = snd_pcm_prepare(playback_handle)) < 0) {
fprintf(stderr, "cannot prepare audio interface for use(%s)\n",
snd_strerror(err));
return err;
}
// Start stream
start_stream(playback_handle, capture_handle, audio_processing_callback, controls_callback, &data, write_to_file, read_from_file);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论