ALSA音频口吃(RTL_FM,Raspberry Pi3)

时间:2018-01-06 19:44:00

标签: c audio raspberry-pi alsa pcm

我一直在使用RTLSDR,特别是rtl_fm,为Raspberry Pi开发一个项目。源代码为here。通常,rtl_fm的使用是rtl_fm -M wbfm -f <frequency in hertz> | aplay -r 32000 -f S16_LE -c 1 。要寻找,您需要通过发送中断来结束该过程,然后以新频率再次运行它。为了避免这种情况,并且还允许它接受套接字命令(例如SEEK_UP等),我决定修改rtl_fm,并使用ALSA直接播放声音。

但我会说实话,我的音频编程技巧仅限于这个项目。我设法让它播放音频,但它不断口吃。 afaik,它不是由欠载引起的(我没有得到-EPIPE错误),并且相同的代码减去我的修改在管道播放时工作正常。

通常,它通过以下方式将音频输出到STDOUT:
rtl_fm.c

<frequency in hertz>

我把它修改为:
rtl_fm_player.c

pthread_rwlock_rdlock(&s->rw);
fwrite(s->result, 2, s->result_len, s->file);
pthread_rwlock_unlock(&s->rw);

根据以下设置播放器(为简洁起见,省略了错误检查):
rtl_fm_player.c

pthread_rwlock_rdlock(&s->rw);
if ((p->pcm_error = snd_pcm_writei(p->pcm_handle, s->result, s->result_len)) == -EPIPE)
{
    snd_pcm_prepare(p->pcm_handle);
}
else if (p->pcm_error < 0)
{
    printf("ERROR. Can't write to PCM device. %s\n", snd_strerror(p->pcm_error));
}
pthread_rwlock_unlock(&s->rw);

播放器状态是存储速率,通道,output_size等的结构.rate = 32000,channels = 1.当前output_size未使用。

完整代码在这里,如果这有助于https://bitbucket.org/ab6393/rtl_fm-player

如果这也有帮助,当rtl_fm被传送给它时,详细记录aplay,假设我错过了设置一些hw参数。

void player_setup(struct player_state * o)
{
    snd_pcm_hw_params_t *params; 
    /* Open the PCM device in playback mode */

    o->pcm_error = snd_pcm_open(&(o->pcm_handle), PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)

    /* Allocate parameters object and fill it with default values*/

    //alloca puts params on the stack, no need to free it.
    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(o->pcm_handle, params);

    /* Update relevant parameters to new values */
    //interleaved
    o->pcm_error = snd_pcm_hw_params_set_access(o->pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)

    //16 bit little endian raw data
    o->pcm_error = snd_pcm_hw_params_set_format(o->pcm_handle, params, SND_PCM_FORMAT_S16_LE)

    //channels
    o->pcm_error = snd_pcm_hw_params_set_channels(o->pcm_handle, params, o->channels)

    //sample rate
    o->pcm_error = snd_pcm_hw_params_set_rate_near(o->pcm_handle, params, &(o->rate), 0)

    /* Write parameters to pcm_handler */
    o->pcm_error = snd_pcm_hw_params(o->pcm_handle, params)

    //snd_pcm_hw_params_get_buffer_size(params, &(o->bufferSize));
    fifo_init(o->fifo, o->output_size * 8);
    o->setup = true;
}

据我所知,该设置与运行aplay相同,但结果不同。如果有人能告诉我我搞砸了什么,那就非常感激了。

0 个答案:

没有答案