繁体   English   中英

在树莓派模拟输出上用于ALSA接收和播放原始PCM的配置

[英]Configuration for ALSA Receiving and Playing Raw PCM on Raspberry Pi Analogue Output

我已经使用PulseAudio和Qt5.4的QAudioOutput在Raspberry Pi的3.5mm耳机插孔模拟输出上成功播放了音频。 音频已通过XBee链接以8位样本从XBee链接以8KHz成功传输。

PulseAudio的延迟很长,因此我决定与libasound(ALSA)链接并直接播放音频。 我的代码在下面,可以成功打开并播放声音,但几乎无法识别,有很多crack啪声和吱吱声。 如果我对着远程麦克风讲话,我很快就会听到Pi发出的耳机刮擦声和吱吱声(但这不是很好的音频)。 我想我的参数搞砸了。

1.)数据以BigEndian传输-QAudioOutput允许您通知其样本为BigEndian。 但是这些是U8样本,所以我需要担心字节顺序吗? 2.)您在下面的配置中看到任何问题吗? 3.)如何确定Pi上输出的ALSA的分片大小? 4.)有人可以解释我应该如何将缓冲区写入音频设备吗?

谢谢!

这是我的代码:

UdpReceiver::UdpReceiver(QObject *parent) :
    QObject(parent)
{

    // Debug
    qDebug() << "Setting up a UDP Socket...";

    // Create a socket
    m_Socket = new QUdpSocket(this);

    // Bind to the 2616 port
    bool didBind = m_Socket->bind(QHostAddress::Any, 0x2616);
    if ( !didBind ) {
        qDebug() << "Error - could not bind to UDP Port!";
    }
    else {
        qDebug() << "Success binding to port 0x2616!";
    }

    // Get notified that data is incoming to the socket
    connect(m_Socket, SIGNAL(readyRead()), this, SLOT(readyRead()));

    // Init to Zero
    m_NumberUDPPacketsReceived = 0;

}

void UdpReceiver::readyRead() {

    // When data comes in
    QByteArray buffer;
    buffer.resize(m_Socket->pendingDatagramSize());

    QHostAddress sender;
    quint16 senderPort;

    // Cap buffer size
    int lenToRead = buffer.size();
    if ( buffer.size() > NOMINAL_AUDIO_BUFFER_SIZE ) {
        lenToRead = NOMINAL_AUDIO_BUFFER_SIZE;
    }

    // Read the data from the UDP Port
    m_Socket->readDatagram(buffer.data(), lenToRead,
                         &sender, &senderPort);

    // Kick off audio playback
    if ( m_NumberUDPPacketsReceived == 0 ) {

        qDebug() << "Received Data - Setting up ALSA Now....";

        // Error handling
        int err;

        // Device to Write to
        char *snd_device_out  = "hw:0,0";

        if ((err = snd_pcm_open (&playback_handle, snd_device_out, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
            fprintf (stderr, "cannot open audio device %s (%s)\n",
                    snd_device_out,
                    snd_strerror (err));
            exit (1);
        }

        if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
            fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        if ((err = snd_pcm_hw_params_any (playback_handle, hw_params)) < 0) {
            fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        if ((err = snd_pcm_hw_params_set_access (playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
            fprintf (stderr, "cannot set access type (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        if ((err = snd_pcm_hw_params_set_format (playback_handle, hw_params, SND_PCM_FORMAT_U8)) < 0) { // Unsigned 8 bit
            fprintf (stderr, "cannot set sample format (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        uint sample_rate = 8000;
        if ((err = snd_pcm_hw_params_set_rate_near (playback_handle, hw_params, &sample_rate, 0)) < 0) { // 8 KHz
            fprintf (stderr, "cannot set sample rate (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        if ((err = snd_pcm_hw_params_set_channels (playback_handle, hw_params, 1)) < 0) { // 1 Channel Mono
            fprintf (stderr, "cannot set channel count (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        if ((err = snd_pcm_hw_params (playback_handle, hw_params)) < 0) {
            fprintf (stderr, "cannot set parameters (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        snd_pcm_hw_params_free (hw_params);

        // Flush handle prepare for playback
        snd_pcm_drop(playback_handle);

        if ((err = snd_pcm_prepare (playback_handle)) < 0) {
            fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                     snd_strerror (err));
            exit (1);
        }

        qDebug() << "Done Setting up ALSA....";

    }

    // Grab the buffer
    m_Buffer = buffer.data();

    // Write the data to the ALSA device
    int error;
    for (int i = 0; i < 10; ++i) {
        if ((error = snd_pcm_writei (playback_handle, m_Buffer, NOMINAL_AUDIO_BUFFER_SIZE)) != NOMINAL_AUDIO_BUFFER_SIZE) {
            fprintf (stderr, "write to audio interface failed (%s)\n",
                     snd_strerror (error));
            exit (1);
        }
    }

    // Count up
    m_NumberUDPPacketsReceived++;

}
  1. 没有。
  2. snd_pcm_hw_params_set_rate_near()会将速率更改为最近的支持速率。 您可能不想要那样。
  3. ALSA没有片段大小。

    它具有缓冲区和周期大小; 您需要根据自己的时间要求进行设置(请参阅ALSA:扬声器的周期大小与麦克风之间的关系 )。

  4. 您不能简单地输出接收到的样本。 您必须将它们重新采样到播放设备的速度(即使使用相同的标称采样率也不完全相同)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM