簡體   English   中英

如何在Raspberry Pi上使用C ++將收到的UDP音頻數據正確寫入ALSA

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

我有2個Raspberry Pis,其中1個將UDP幀的音頻數據傳輸到另一個Raspberry Pi。 收到的UDP數據包各為160字節。 傳輸的Raspberry Pi正在發送8KHz 8位單聲道樣本。 接收Raspberry Pi使用帶有QUDPSocket的Qt 5.4.0並嘗試使用ALSA播放接收的數據。 代碼如下。 每當字節到達接收Raspberry Pi時觸發“readyRead”信號,緩沖區就會寫入ALSA。 我在接收Pi上的耳機插孔中發出了非常低聲和毛躁的聲音 - 但它是可識別的。 所以它工作但聽起來很糟糕。

  1. 對於ALSA,我的配置是否有任何明顯的錯誤?
  2. 我應該如何使用snd_pcm_writei將收到的UDP數據包寫入ALSA?

謝謝你的任何建議。

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

}

我不理解代碼中的“封頂緩沖區大小”部分。 如果傳入的數據大於您的任意NOMINAL_AUDIO_BUFFER_SIZE,那么您將切斷傳入的數據。 你試過刪除那段代碼嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM