gpt4 book ai didi

linux - 将字节流式传输到 ALSA 播放设备

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:21:08 24 4
gpt4 key购买 nike

我在使用 libasound 将随机字节写入 ALSA 播放设备时遇到了很多麻烦。最终,我的目标是能够通过网络路由播放流并在远程设备上播放。

this question 中提供的代码将 WAV 文件读入内存并通过 snd_pcm_writei 将其写入驱动程序并且它可以工作。然而,这段代码的作用与我尝试做的事情之间的一个关键区别是,我没有立即获得所有可用的数据。我希望在数据可用时流式传输数据。

根据我的需要调整上面的示例代码,我最终得到了这个:

#include <stdio.h>
#include <unistd.h>
#include <alsa/asoundlib.h>

static snd_pcm_t *PlaybackHandle;

int init_playback(const char *device, int samplerate, int channels) {
int err;

printf("Init parameters: %s %d %d\n", device, samplerate, channels);

if((err = snd_pcm_open(&PlaybackHandle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Can't open audio %s: %s\n", device, snd_strerror(err));
return -1;
}

if ((err = snd_pcm_set_params(PlaybackHandle, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, channels, samplerate, 1, 500000)) < 0) {
printf("Can't set sound parameters: %s\n", snd_strerror(err));
return -1;
}
return 0;
}

int play_bytes(const void *bytes, int len) {
snd_pcm_uframes_t frames, count;
snd_pcm_uframes_t bufsize, period_size;
frames = 0;
count = 0;

snd_pcm_prepare(PlaybackHandle);

snd_pcm_get_params(PlaybackHandle, &bufsize, &period_size);
printf("bufsize=%d\n", (int) bufsize);

do {
int remaining = len - count;
int buflen = remaining < bufsize ? remaining : bufsize;
frames = snd_pcm_writei(PlaybackHandle, bytes + count, buflen);
// If an error, try to recover from it
if (frames == -EPIPE) {
printf("EPIPE\n");
snd_pcm_prepare(PlaybackHandle);
}
if (frames < 0) {
printf("Recovering\n");
frames = snd_pcm_recover(PlaybackHandle, frames, 0);
}
if (frames < 0)
{
printf("Error playing wave: %s\n", snd_strerror(frames));
break;
}

// Update our pointer
count += frames;
//printf("count=%d len=%d\n", (int)count, len);

} while (count < len);

// Wait for playback to completely finish
if (count == len)
snd_pcm_drain(PlaybackHandle);
return 0;
}

int close_playback() {
snd_pcm_close(PlaybackHandle);
return 0;
}

int main(int argc, char **argv) {
if(argc < 1) {
printf("Usage: %s <WAV-file>\n", argv[0]);
return -1;
}

int fd;
unsigned long long len;

fd = open(argv[1], O_RDONLY);
// Find the length
len = lseek(fd, 0, SEEK_END);

// Skip the first 44 bytes (header)
lseek(fd, 44, SEEK_SET);
len -= 44;

char *data = malloc(len);
read(fd, data, len);

init_playback("default", 44100, 2);
play_bytes(data, len);
close_playback();
return 0;
}

这段代码可以用gcc playback.c -o playback -lasound编译。我正在使用的 WAV 文件可以找到 here .

当我运行此代码片段时,我根据 bufsize 对传入数据进行分块,根据分块大小,音频片段会在播放中重复出现。大块大小比小块大小产生更少的重复。结合音频的声音,我相信每个 block 末尾的一个小片段正在重复。

我使用的参数是:

  • 采样率:44100
  • channel :2

为什么一次性发送整个 WAV 文件有效,而发送大块文件却无效?如何将音频数据 block 发送到驱动程序并使其正常播放?

最佳答案

    frames = snd_pcm_writei(PlaybackHandle, bytes + count, buflen);
count += frames;

snd_pcm_writei() 测量大小,但您将其视为字节。所以你只跳过了刚刚播放的数据的四分之一。

关于linux - 将字节流式传输到 ALSA 播放设备,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42753453/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com