简体   繁体   English

如何在Raspberry Pi上使用C ++将收到的UDP音频数据正确写入ALSA

[英]How to Properly Write Received UDP Audio Data to ALSA with C++ on Raspberry Pi

I have 2 Raspberry Pis and 1 of them transmits UDP frames of Audio data to the other Raspberry Pi. 我有2个Raspberry Pis,其中1个将UDP帧的音频数据传输到另一个Raspberry Pi。 The UDP Packets received are 160 Bytes each. 收到的UDP数据包各为160字节。 The transmitting Raspberry Pi is sending 8KHz 8-bit Mono samples. 传输的Raspberry Pi正在发送8KHz 8位单声道样本。 The receiving Raspberry Pi uses Qt 5.4.0 with QUDPSocket and tries to play the received data with ALSA. 接收Raspberry Pi使用带有QUDPSocket的Qt 5.4.0并尝试使用ALSA播放接收的数据。 The code is below. 代码如下。 Each time the "readyRead " signal is fired when bytes arrive on the receiving Raspberry Pi, the Buffer is written to ALSA. 每当字节到达接收Raspberry Pi时触发“readyRead”信号,缓冲区就会写入ALSA。 I have very Choppy and Glitchy sound coming out of the headphone Jack on the Receiving Pi - but it is recognizable. 我在接收Pi上的耳机插孔中发出了非常低声和毛躁的声音 - 但它是可识别的。 So it is working but sounds Terrible. 所以它工作但听起来很糟糕。

  1. Is there anything glaringly wrong with my configuration below for ALSA? 对于ALSA,我的配置是否有任何明显的错误?
  2. How should I approach writing the received UDP packets to ALSA with snd_pcm_writei? 我应该如何使用snd_pcm_writei将收到的UDP数据包写入ALSA?

Thank you for any suggestions. 谢谢你的任何建议。

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 (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;
    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++;

}

I'm not understanding the "capping the buffer size" part of the code. 我不理解代码中的“封顶缓冲区大小”部分。 If the incoming data is larger than your arbitrary NOMINAL_AUDIO_BUFFER_SIZE then you're chopping off that incoming data. 如果传入的数据大于您的任意NOMINAL_AUDIO_BUFFER_SIZE,那么您将切断传入的数据。 Have you tried removing that bit of code? 你试过删除那段代码吗?

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

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