【问题标题】:Alsa plays audio get from CAN FDAlsa 播放来自 CAN FD 的音频
【发布时间】:2022-02-22 19:02:54
【问题描述】:

我正在尝试使用 Alsa 库将我从 CAN FD 通信中获得的音频复制到我的耳机中。我不太明白如何正确配置 Alsa 的参数,以便能够听到我从 CAN FD 获得的声音。

static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 16000; /* stream rate */
static unsigned int channels = 1; /* count of channels */
static unsigned int buffer_time = 40000; /* ring buffer length in us */
static unsigned int period_time = 120000; /* period time in us */
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0;                            /* produce poll event after each period */
int size;

while (1) {
        do {
            nbytes = read(s, &frame, sizeof(struct canfd_frame));
        } while (nbytes == 0);
        for (x = 0; x < 64; x = x + 2) {
            buffer[a] = ((uint32_t) frame.data[x] << 8)
                    | ((uint32_t) (frame.data[x + 1]));
            a++;
        }
        //err=snd_pcm_writei(handle,buffer,32);
        //printf("Datos = %d\n", err);
        memcpy(total1 + i * 32, buffer, 32 * sizeof(uint32_t));
        i++;
        a = 0;
        if (i == 500) {
            buffer_length=16000;
            ptr = total1;
            while(buffer_length > 0){
                err = snd_pcm_writei(handle, ptr, 16000);
                printf("Datos = %d\n", err);
                snd_pcm_avail_delay(handle, &availp, &delayp);
                //printf("available frames =%ld  delay = %ld  z = %d\n", availp, delayp, z);
                if (err == -EAGAIN)
                    continue;
                if(err < 0){
                    err=snd_pcm_recover(handle, err, 1);
                }
                else{
                    ptr += err * channels;
                    buffer_length -= err;
                    z++;
                }
                if(err<0){
                    printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
                    break;
                }
        }
        i = 0;
    }

这是我的代码的一部分,我不认为发布整个代码是值得的。我不明白我应该给 buffer_time、period_time 哪些值以及如何能够实时收听我通过 CAN FD 得到的内容。我正在使用 snd_pcm_writei,插入一个缓冲区,其中填充了一些从 CAN FD 获得的样本。我不知道应该为缓冲区和“frames”变量指定哪个大小,这是另一个我不太了解的变量,尽管我已经阅读了一些相关内容。

知道我应该如何配置我的系统吗? (buffer_time, period_time, buffer_size, 帧,...) 我尝试过使用不同的缓冲区和帧大小,但我认为我不明白它是如何正常工作的。如何计算 snd_pcm_writei() 的帧和缓冲区的大小,以便实时收听音频?

我应该使用两个不同的线程吗?一个用 CAN FD 信息创建缓冲区,另一个处理缓冲区和音频输出?

提前致谢, 安德。

【问题讨论】:

  • 作为练习,我可以建议您尝试解决以下问题: 生成并播放正弦波,其频率作为变量传入。以下是要解决的子问题: 1) 给定一定的采样率,给定持续时间的缓冲区应该有多少个样本? 2) 生成正弦波时,样本索引如何转换为波形的相位? 3) 如何用 ALSA 回放这样的缓冲区?
  • 据我了解: 1) Buffer_size = 采样率 * num_channels*time(s) 这是正确的吗? 2)样本索引是什么意思?抱歉,我不明白:(。3)对于我读到的内容,我只需在 snd_pcm_writei(handle,buffer,frames) 中引入带有 frame_size = channels *bytes_per_sample 的缓冲区?或者我可以使用另一个 frame_size 来分割我的缓冲区吗?像 buffer_size/2 这样的东西?对于我读到的更大的缓冲区,CPU 使用率更低,但延迟更高。实时的最佳方法是什么?
  • 我终于可以听到我从 CAN FD 到耳机中的音频了,你可以关闭这个任务。
  • 请在答案中写下您为解决问题所做的工作,以便其他通过互联网搜索偶然发现此问题的人也能找到答案。见xkcd.com/979

标签: c embedded-linux alsa can-bus


【解决方案1】:

我终于设法通过耳机听到了自己的声音。我已经更改了我之前发布的配置,以便使用从 CAN FD 获得的数据对其进行同步。如果有人需要示例,我将在此处发布我的部分代码。必须处理此类缓冲区的最重要部分是处理填充时间和通信时间。处理时间并相应地配置 Alsa 参数可以更轻松地处理缓冲区。

static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
static unsigned int rate = 22000; /* stream rate */ 
static unsigned int channels = 1; /* count of channels */
static unsigned int buffer_time = 1000; /* ring buffer length in us */ 
static unsigned int period_time = 10000; /* period time in us */ 
static int resample = 1; /* enable alsa-lib resampling */
static int period_event = 0; /* produce poll event after each period */
int size;

static snd_pcm_sframes_t buffer_size;
static snd_pcm_sframes_t period_size;
static snd_output_t *output = NULL;
snd_pcm_sframes_t delayp;
snd_pcm_sframes_t availp;

snd_pcm_uframes_t frames;

static void write_loop(snd_pcm_t *handle) {

    uint32_t *buffer = malloc(16000 * sizeof(uint32_t));

    uint32_t *total1 = malloc(16000 * sizeof(uint32_t)); // array to hold the result

    while (1) {
        do {
            nbytes = read(s, &frame, sizeof(struct canfd_frame));
        } while (nbytes == 0);
        for (x = 0; x < 64;x = x + 2) {
            buffer[a] = ((uint32_t) frame.data[x] << 8)
                    | ((uint32_t) (frame.data[x + 1]));
            //buffer[a]=frame.data[x];
            a++;
        }
        i++;
        if (i == 250) {
            memcpy(total1, buffer, 16000 * sizeof(uint32_t));
            //printf("Address = %lu \n",(unsigned long)total1);
            flag = 1;
            buffer_length = 16000;
            i = 0;
            a = 0;
        }
        if (flag == 1) {
            while(buffer_length > 0) {
                 snd_pcm_prepare(handle);
                err = snd_pcm_writei(handle, total1, buffer_length);
                //printf("Datos = %d\n", err);
                snd_pcm_avail_delay(handle, &availp, &delayp);
                 //printf("available frames =%ld  delay = %ld\n",availp,delayp);
                if (err == -EAGAIN)
                    continue;
                if (err < 0) {
                    err = snd_pcm_recover(handle, err, 1);
                } else {
                    ptr += err * channels;
                    buffer_length -= err;
                    z++;
                }
                if (err < 0) {
                    printf("snd_pcm_writei failed: %s\n", snd_strerror(err));
                    break;
                }
            }
            flag = 0;
        }
    }
}

【讨论】:

    猜你喜欢
    • 2017-08-09
    • 2014-07-09
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    相关资源
    最近更新 更多