我需要使用嵌入式
Linux系统将音频从收音机发送到辅助系统.
辅助系统需要建立一个需要几秒钟的通信信道.
因此,如果我不想失去音频的开头,我需要一种方法来录制声音并以自定义延迟播放(最多几秒).
应该可以启动arecord将音频记录在tmpfs文件系统的文件中,并且当传入通信时,启动aplay.
但在这种情况下,开始仍然会丢失,因为要记录的信号来得太晚了.
Linux上是否有一个程序可以在RAM中的环形缓冲区中连续录制声音,并且能够根据需要自定义延迟播放?
如果没有,在嵌入式系统上编写这样一个程序的最佳库是什么? alsa还是其他什么?
解决方法
这是一个简单的C程序,它将在管道输入和输出之间保持循环缓冲区.在|中使用buffer_program |出.错误检查省略.坚固性不保证.给出了一般的想法.
测试脚本(但实际上,因为它的循环缓冲区需要管道中的数据,以便它只需要流中的任何块.或者只是使缓冲区大于数据):
cat some.wav | ./circular_buffer 100000 | (sleep 1 && aplay)
circular_buffer.c:
/** * This program simply maintains a circular buffer of a given size indefinitely. */ #include <stdio.h> #include <stddef.h> #include <unistd.h> #include <stdlib.h> #include <stdbool.h> /* C99 only */ #include <sys/select.h> #include <errno.h> #include <fcntl.h> int c_read(int fd,char * buf,unsigned int size,unsigned int * head_in,unsigned int * tail_in); int c_write(int fd,unsigned int * tail_in); bool empty_buf(unsigned int head,unsigned int tail); bool setblock(int fd,bool block); #define FD_SET_SET(set,fd,max) FD_SET(fd,&set); max = ((fd > max) ? fd : max); #define FD_SET_UNSET(set,max) FD_CLR(fd,&set); max = ((fd == max) ? max - 1 : max); //not ideal. Do while ISFDSET... int main(int argc,char **argv) { char * buf; unsigned int buf_size = 0; unsigned int buf_head = 0; unsigned int buf_tail = 0; // Check args. if(argc != 2) { fprintf(stderr,"Usage: %s <buffer size in bytes>\n",__FILE__); exit(EXIT_FAILURE); } sscanf(argv[1],"%d",&buf_size); buf_size = ( buf_size < 2 ) ? 2 : buf_size; // Note the usable buffer space is buf_size-1. fprintf(stderr,"Allocating %d\n",buf_size); buf = (char*)malloc(buf_size); bool done_reading = false; int maxfd = 0; fd_set r_set,w_set,r_tempset,w_tempset; setblock(STDIN_FILENO,false); setblock(STDOUT_FILENO,false); FD_ZERO(&r_set); FD_ZERO(&w_set); FD_ZERO(&r_tempset); FD_ZERO(&w_tempset); FD_SET_SET(r_tempset,STDIN_FILENO,maxfd); FD_SET_SET(w_tempset,STDOUT_FILENO,maxfd); r_set = r_tempset; while(true) { select((maxfd + 1),&r_set,&w_set,NULL,NULL); if(FD_ISSET(STDIN_FILENO,&r_set)) { int c = c_read(STDIN_FILENO,buf,buf_size,&buf_head,&buf_tail); if(c == -1) { // EOF,disable select on the input. fprintf(stderr,"No more bytes to read\n"); done_reading = true; FD_ZERO(&r_set); } } if(!done_reading) { r_set = r_tempset; } if(FD_ISSET(STDOUT_FILENO,&w_set)) { c_write(STDOUT_FILENO,&buf_tail); } if(!empty_buf(buf_head,buf_tail)) { // Enable select on write whenever there is bytes. w_set = w_tempset; } else { FD_ZERO(&w_set); if(done_reading) { // Finish. fprintf(stderr,"No more bytes to write\n"); break; } } } fflush(stderr); return 0; } bool empty_buf(unsigned int head,unsigned int tail) { return head == tail; } /** * Keep reading until we can read no more. Keep on pushing the tail forward as we overflow. * Expects fd to be non blocking. * @returns number of byte read,0 on non stopping error,or -1 on error or EOF. */ int c_read(int fd,unsigned int * tail_in) { fprintf(stderr,"In c_read()\n"); unsigned int head = *head_in; unsigned int tail = *tail_in; bool more_bytes = true; int n = 0; int c = 0; while(more_bytes) { bool in_front = tail > head; fprintf(stderr,"Read %d %d %d\n",size,head,tail); n = read(fd,buf+head,size - head); if(n == -1) { more_bytes = false; if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { // Not EOF but the read would block. c = 0; } else { c = -1; } } else if(n == 0) { // EOF. No more bytes possible. more_bytes = false; c = -1; } else if(n != (size - head)) { // if not full read adjust pointers and break. more_bytes = false; c += n; head = (head+n)%size; if(in_front && (head >= tail || head == 0)) { tail = (head+1)%size; } } else { c = 0; head = 0; tail = (tail == 0) ? 1 : tail; } } *head_in = head; *tail_in = tail; return c; } /** * Try flush the buffer to fd. fd should be non blocking. */ int c_write(int fd,"In c_write()\n"); unsigned int head = *head_in; unsigned int tail = *tail_in; int n = 0; fprintf(stderr,"Write %d %d %d\n",tail); if(tail < head) { n = write(fd,buf+tail,head-tail); tail += n; } else if(head < tail) { n = write(fd,size-tail); if(n == size-tail) { n = write(fd,head); tail = n; } } *head_in = head; *tail_in = tail; return n; } bool setblock(int fd,bool block) { int flags; flags = fcntl(fd,F_GETFL); if (block) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; fcntl(fd,F_SETFL,flags); return true; }