- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在编写一个用于音频流的嵌入式应用程序。嵌入式应用程序将接收通过 wifi 发送的音频数据包,缓冲数据包,然后将音频数据发送到解码器芯片。我编写了一个环形缓冲区实现(在 stackoverflow 上一篇优秀文章的帮助下),但有时会出现一些奇怪的行为。在音频方面,我在播放过程中听到歌曲的某些部分重复。我发现这是由于尾指针被设置到缓冲区的开头两次。
(在我的实现中,头指针标记有效数据的结束,而尾指针标记有效数据的开始)
例如,我看到:
typedef struct ring_buffer
{
UINT8 *buffer; /* data buffer */
UINT8 *buffer_end; /* end of data buffer */
size_t capacity; /* maximum number of mp3Bytes in the buffer */
size_t count; /* number of mp3Bytes in the buffer */
size_t typesize; /* size of each mp3Byte in the buffer */
UINT8 *head; /* ring buffer head pointer */
UINT8 *tail; /* ring buffer tail pointer */
} ring_buffer;
PUBLIC UINT8
AppAudioStream_RingBufInit(ring_buffer *rb, size_t capacity, size_t typesize)
{
/* alloc buffer of size capacity * typesize */
rb->buffer = malloc(capacity * typesize);
if(rb->buffer == NULL)
{
printf("ring buffer init fail\r\n");
return RING_BUF_INIT_FAIL;
}
/* init rb buffer to 0 */
memset(rb->buffer, 0, capacity * typesize);
/* rb struct element init */
rb->capacity = capacity;
rb->buffer_end = rb->buffer + capacity * typesize;
rb->count = 0;
rb->typesize = typesize;
rb->head = rb->buffer;
rb->tail = rb->buffer;
return RING_BUF_INIT_DONE;
}
PUBLIC VOID
AppAudioStream_RingBufWrite(ring_buffer *rb, UINT8 *mp3Byte)
{
/* default: allow overwriting if ring buffer is full */
memcpy(rb->head, mp3Byte, rb->typesize);
rb->head = rb->head + rb->typesize;
if(rb->head == rb->buffer_end) {
printf("head back to start\r\n");
rb->head = rb->buffer;
}
if(rb->count == rb->capacity) {
printf("buffer full\r\n");
if (rb->head > rb->tail)
rb->tail = rb->tail + rb->typesize;
} else {
rb->count++;
}
}
PUBLIC VOID
AppAudioStream_RingBufRead(ring_buffer *rb, UINT8 *mp3Byte)
{
/* insert 'comfort noise' if the ring buffer is empty */
if(rb->count == 0){
printf("buffer empty\r\n");
*mp3Byte = NOISE_BYTE;
} else {
/* copy data to mp3Byte and increase tail pointer */
memcpy(mp3Byte, rb->tail, rb->typesize);
rb->tail = rb->tail + rb->typesize;
if(rb->tail == rb->buffer_end) {
printf("TAIL back to start\r\n");
printf("Tbuffer count: %i\r\n", rb->count);
rb->tail = rb->buffer;
}
rb->count--;
}
}
while (1)
{
AppAudioStream_BufRecv(sd, dataLen, &addr);
}
PUBLIC VOID
AppAudioStream_BufRecv(int sd, INT32 dataLen, struct sockaddr_in *addr)
{
INT32 addrlen = sizeof(struct sockaddr_in);
UINT8 j, i = 0;
UINT8 *audioByte;
/* listen to incoming audio data packets */
dataLen = recvfrom(sd, (char *) appRxBuf, sizeof(appRxBuf), 0,
(struct sockaddr *)&addr, &addrlen);
/* set pointer to first element in recieve buffer */
audioByte = appRxBuf;
/* buffer received packets into FIFO */
while (dataLen > 0)
{
/* write 1 byte into audio FIFO */
AppAudioStream_RingBufWrite(&audioFIFO, audioByte);
/* increase pointer index and update # of bytes left to write */
audioByte++;
dataLen--;
}
/* wait until buffer is 2/3 full to start decoding */
if (audioFIFO.count >= FIFO_TWO_THIRD_FULL
&& audioStreamStatus == GSN_STREAM_BUFFERING) {
audioStreamStatus = GSN_STREAM_START;
//printf("stream start\r\n");
}
}
PRIVATE VOID
AppAudioStream_DecoderCb(UINT32* pDummy, UINT32 TimerHandle)
{
UINT8 spiWriteCount = 0;
UINT8 mp3Byte;
int i = 0;
GSN_SPI_NUM_T spiPortNumber = GSN_SPI_NUM_0;
/* read 32 bytes of data from FIFO and write to SPI */
while (spiWriteCount < DATA_WRITE_AMT)
{
/* set stream status to decoding */
audioStreamStatus = GSN_STREAM_DECODING;
/* read 1 byte of audio data from FIFO */
AppAudioStream_RingBufRead(&audioFIFO, &mp3Byte);
/* write 1 byte of audio data out to VS1053 */
AppSpi_SdiByteWrite(spiPortNumber, &mp3Byte);
/* increase byte written count */
spiWriteCount++;
}
}
最佳答案
如果您从回调读取此环形缓冲区并从其他地方写入它,那么显然您会遇到各种奇怪的错误,因为环形缓冲区缺乏保护。您需要添加互斥锁、信号量、中断禁用或任何适用于您的特定系统的内容。
此外,回调和应用程序其余部分之间共享的所有变量都应声明为 volatile,以防止危险的优化器错误 (*)。除此之外,可能还需要使用互斥锁保护此类变量以防止竞争条件。
如果上述任何错误是原因,压力测试的一个好方法是创建一个多线程应用程序。创建 10+ 个写入缓冲区的线程,以及 10+ 个从中读取和打印的线程。记录输出并查看是否打印了奇数值或垃圾。
(*)(此评论与线程安全无关,所以请不要发表关于 volatile 不足以实现线程安全的评论,因为我从未说过它是,而且我还不会进行那种愚蠢的辩论再次。)
关于c - C 尾指针问题中的环形缓冲区(用于音频流),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10606562/
我正在尝试从网站(名称)“抓取”一些数据。我知道如何获得列表中的第一个名字——但我需要以同样的方式保存几千个名字。 这是我的代码: library(rvest) library(tidyverse)
我正在尝试制作一个环形 UIBezierPath 用作 CAShapeLayer 的 path 以下产生一个循环路径: let radius = 100.0 let circularPath = UI
如何在 1 分钟后停止 setTimeout。由于循环,它继续运行。TIA var image1 = new Image() image1.src = "images/slide1.jpg"
我现在这个问题发布了更多次,但我还没有解决我的问题。在我的例子中,foregroundColor 不工作。即使 foregroundColor 没有选择任何颜色,环也不会出现 darkGray 颜色。
public class Tester { // instance variables - replace the example below with your own Scanne
来自澳大利亚的投票问题: 一个机器人会不断地输入信息,它可以达到 1000 行。他将输入的内容示例: "1 2 3 2 1 3 2 3 1 1 2 3 3 1 2 " 我怎么知道他什么时候输入完信息?
有人可以启发如何进行这项工作吗?所以现在我有一个 do/while 循环,里面有一个开关。开关由一个 int 选择处理,scanf 是“%d”。但是,如果我写一个不同于数字的字符符号,如 a、b、c.
我是一名优秀的程序员,十分优秀!