1
votes

First, I'm trying to send audio data from one process to other via the UDP protocol on localhost.

First, the program reads voice from the microphone and sends it via UDP socket:

#include <QApplication>
#include <QIODevice>
#include <QtMultimediaKit/QAudioOutput>
#include <QtMultimediaKit/QAudioInput>
#include <QtMultimediaKit/QAudioFormat>
#include <QUdpSocket>

int main(int argc, char** argv){
    QApplication app(argc, argv);
    QAudioFormat format;
    format.setSampleRate(128000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);
    QAudioInput* input = new QAudioInput(format);
    QUdpSocket* socket = new QUdpSocket();
    socket->connectToHost("127.0.0.1", 1002);
    input->start(socket);
    return app.exec();
}

I check data sending in by Wireshark, and I think data is sent. So many UDP packages per second on the 1002 port.

The second program should read UDP packages and play it in the output device:

#include "UDPPlayer.h"
#include <QDebug>

UDPPlayer::UDPPlayer(){
    socket = new QUdpSocket();
    socket->bind(1002);
    QAudioFormat format;
    format.setSampleRate(128000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);
    output = new QAudioOutput(format);
    connect(socket, SIGNAL(readyRead()), this, SLOT(playData()));
}

void UDPPlayer::playData(){
    qDebug() << "data";
    output->start(socket);
}

The problem is the following: playData() is never called ("data" is never printed). Does it mean that the socket is never readyRead? But I see these packages by Wireshark. What am I doing wrong?

1
A couple of questions: 1) In your second program, are you instantiating a QApplication and calling app.exec() on it? (I assume you are, but it isn't shown) Also, just out of curiosity: why a sample rate of 128000? That seems like an unusual audio sampling rate -- more common sample rates would be 44100, 48000, 96000, or 192000)Jeremy Friesner
If you take a look at the docs for QUdpSocket, you can see that if you're using a slot to receive the readyRead signal you need to to read the datagram or you won't get more datagrams. From the docs: Note: An incoming datagram should be read when you receive the readyRead() signal, otherwise this signal will not be emitted for the next datagram.Andrew Dolby

1 Answers

2
votes

You need make sure that the format used is supported by the input and output devices.

You also need to create a QIODevice from the output device, in order to write data to it, such data you will get with socket->readDatagram()

And you need to do something like this:

main.cpp:

#include <QApplication>
#include <QIODevice>
#include <QtMultimedia/QAudioOutput>
#include <QtMultimedia/QAudioInput>
#include <QtMultimedia/QAudioFormat>
#include <QUdpSocket>
#include "udpplayer.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    new UDPPlayer();

    QAudioFormat format;
    format.setSampleRate(128000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);

    //If format isn't supported find the nearest supported
    QAudioDeviceInfo info(QAudioDeviceInfo::defaultInputDevice());
    if (!info.isFormatSupported(format))
        format = info.nearestFormat(format);

    QAudioInput* input = new QAudioInput(format);
    QUdpSocket* socket = new QUdpSocket();
    socket->connectToHost("127.0.0.1", 1002);
    input->start(socket);

    return a.exec();
}

udpplayer.h:

#include <QObject>
#include <QtMultimedia/QAudioOutput>
#include <QtMultimedia/QAudioInput>
#include <QtMultimedia/QAudioFormat>
#include <QUdpSocket>

class UDPPlayer : public QObject
{
    Q_OBJECT
public:
    explicit UDPPlayer(QObject *parent = 0);

private slots:
    void playData();

private:
    QAudioOutput *output;
    QUdpSocket *socket;
    QIODevice *device;
};

udpplayer.cpp:

UDPPlayer::UDPPlayer(QObject *parent) : QObject(parent)
{
    socket = new QUdpSocket();
    socket->bind(1002);
    QAudioFormat format;
    format.setSampleRate(128000);
    format.setChannelCount(1);
    format.setSampleSize(16);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);

    QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
    if (!info.isFormatSupported(format))
        format = info.nearestFormat(format);

    output = new QAudioOutput(format);
    device = output->start();
    connect(socket, SIGNAL(readyRead()), this, SLOT(playData()));
}

void UDPPlayer::playData()
{
    //You need to read datagrams from the udp socket
    while (socket->hasPendingDatagrams())
    {
        QByteArray data;
        data.resize(socket->pendingDatagramSize());
        socket->readDatagram(data.data(), data.size());
        device->write(data.data(), data.size());
    }
}