UltraCoder
@UltraCoder

[Qt] QUdpSocket::readyRead

Ох, здравствуйте, товарищи. Пишу курсовую работу: голосовая связь по UDP-протоколу на Qt.
Пишу уже несколько недель, все не могу пофиксить проблему.
Реализовал захват звука и отправку его по UDP удаленному хосту. И, как показывает, Wireshark, отправка работает отлично. А вот с получением пакетов проблема: звук всегда передается только в одну сторону, на другой же ничего не слышно, и, что любопытно, QUdpSocket не генерирует сигнал readyRead, хотя должен. Может быть я чего не понимаю, а может баг Qt. В любом случае, прошу помощи у специалистов. Вот код, отвечающий за передачу и прием датаграм:
#include <QObject>
#include <QIODevice>
#include <QUdpSocket>
#include <QHostAddress>
#include <QAudioInput>
#include <QAudioOutput>
#include <QDebug>

// Function returns constant audio format of all audio streams.
QAudioFormat GetStreamAudioFormat(void);

// Class produces a device to send audio over the network.
class AudioTransmitter : public QIODevice
{
    Q_OBJECT
    public:
        QUdpSocket socket;
        QHostAddress localHOST;
        quint16 localPORT;
        QHostAddress remoteHOST;
        quint16 remotePORT;

        AudioTransmitter(QHostAddress localHost, quint16 localPort, QHostAddress remoteHost, quint16 remotePort, QObject *parent);
        qint64 writeData(const char *data, qint64 len);
        qint64 readData(char *data, qint64 maxlen);
};

// Class produces a device to recieve audio from the network.
class AudioReciever : public QIODevice
{
    Q_OBJECT
    public:
        QUdpSocket socket;
        QHostAddress localHOST;
        quint16 localPORT;
        QHostAddress remoteHOST;
        quint16 remotePORT;

        AudioReciever(QHostAddress localHost, quint16 localPort, QHostAddress remoteHost, quint16 remotePort, QObject *parent);
        qint64 readData(char *data, qint64 maxlen);
        qint64 writeData(const char *data, qint64 len);
        bool isSequential(void) const;
        bool seek(qint64 pos);
};

class VoIPClient : public QObject
{
    Q_OBJECT
    public:
        explicit VoIPClient(QObject *parent = 0);
        ~VoIPClient(void);

        void SetLocalHost(QHostAddress HOST);
        void SetLocalPort(quint16 PORT);
        void SetRemoteHost(QHostAddress HOST);
        void SetRemotePort(quint16 PORT);

        void GetUserInfo(QString LOGIN);

    public slots:
        void Call(void);
        void FinishCall(void);
        void ResumePlaying(void);
        void ResumePlaying(QAudio::State);

    private slots:
        void StartPlaying(void);

    private:
        QHostAddress localHOST;
        QHostAddress remoteHOST;
        quint16 localPORT;
        quint16 remotePORT;

        QAudioInput * audio_input;
        QAudioOutput * audio_output;
        AudioTransmitter * transmitter;
        AudioReciever * reciever;

        void StartConversation(void);
        void StopConversation(void);        
};


QAudioFormat GetStreamAudioFormat(void)
{
    QAudioFormat format;
    format.setSampleRate(8000);
    format.setChannels(1);
    format.setSampleSize(8);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    format.setSampleType(QAudioFormat::UnSignedInt);

    QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
    if (!info.isFormatSupported(format))
    {
        qDebug()<< "default format not supported try to use nearest";
        format = info.nearestFormat(format);
    }

    return format;
}

//////////////////////////////////
// AudioTransmitter Class
//////////////////////////////////

AudioTransmitter::AudioTransmitter(QHostAddress localHost, quint16 localPort, QHostAddress remoteHost, quint16 remotePort, QObject *parent)
    : QIODevice(parent)
{
    localHOST = localHost;
    localPORT = localPort;
    remoteHOST = remoteHost;
    remotePORT = remotePort;
}

qint64 AudioTransmitter::writeData(const char *data, qint64 len)
{
    qint64 writtenBytes = socket.writeDatagram(data, len, remoteHOST, remotePORT);
    qDebug() << "Sent " << writtenBytes << " bytes.";
    return writtenBytes;
}

qint64 AudioTransmitter::readData(char *data, qint64 maxlen)
{
    Q_UNUSED(data);
    Q_UNUSED(maxlen);
    qDebug() << "IOError: device is write-only.";
    return 0;
}

//////////////////////////////////
// AudioReciever Class
//////////////////////////////////

AudioReciever::AudioReciever(QHostAddress localHost, quint16 localPort, QHostAddress remoteHost, quint16 remotePort, QObject *parent)
    : QIODevice(parent)
{
    localHOST = localHost;
    localPORT = localPort;
    remoteHOST = remoteHost;
    remotePORT = remotePort;

    connect(&socket, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
    if (socket.bind(localHOST, localPORT, QUdpSocket::DontShareAddress))
        qDebug() << "Successfully binded to" << localHOST.toString() << ":" << localPORT << ".";

}

qint64 AudioReciever::readData(char *data, qint64 maxlen)
{
    qint64 readBytes = socket.readDatagram(data, maxlen);
    qDebug() << "Recieved " << readBytes << " bytes.";
    return readBytes;
}

qint64 AudioReciever::writeData(const char *data, qint64 len)
{
    Q_UNUSED(data);
    Q_UNUSED(len);
    qDebug() << "IOError: device is read-only.";
    return 0;
}

bool AudioReciever::isSequential(void) const
{
    return true;
}

bool AudioReciever::seek(qint64 pos)
{
    Q_UNUSED(pos);
    return false;
}

VoIPClient::VoIPClient(QObject *parent) : QObject(parent)
{
}

VoIPClient::~VoIPClient(void)
{
}

void VoIPClient::Call(void)
{
    StartConversation();
}

void VoIPClient::FinishCall(void)
{
    StopConversation();
}

void VoIPClient::StartConversation(void)
{
    QAudioFormat format = GetStreamAudioFormat();
    audio_input = new QAudioInput(format, this);
    audio_output = new QAudioOutput(format, this);
    transmitter = new AudioTransmitter(localHOST, localPORT, remoteHOST, remotePORT, this);
    reciever = new AudioReciever(localHOST, localPORT, remoteHOST, remotePORT, this);

    //connect(audio_output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(ResumePlaying(QAudio::State)));
    connect(reciever, SIGNAL(readyRead()), this, SLOT(ResumePlaying()));

    transmitter->open(QIODevice::WriteOnly | QIODevice::Truncate);
    reciever->open(QIODevice::ReadOnly | QIODevice::Unbuffered);

    audio_input->start(transmitter);
    audio_output->start(reciever);



    qDebug() << "Started conversation with" << remoteHOST.toString() << ".";
}

void VoIPClient::StopConversation(void)
{
    audio_input->stop();
    audio_output->stop();
    transmitter->close();
    reciever->close();

    delete audio_input;
    delete audio_output;
    delete transmitter;
    delete reciever;

    qDebug() << "Finished conversation.";
}

void VoIPClient::StartPlaying(void)
{
    audio_output->start(reciever);
}

void VoIPClient::ResumePlaying(void)
{
    if (audio_output->state() != QAudio::ActiveState)
    {
        audio_output->stop();
        audio_output->start(reciever);
    }
}

void VoIPClient::ResumePlaying(QAudio::State state)
{
    if (state != QAudio::ActiveState)
    {
        audio_output->stop();
        audio_output->start(reciever);
    }
}

void VoIPClient::SetLocalHost(QHostAddress HOST)
{
    localHOST = HOST;
}

void VoIPClient::SetLocalPort(quint16 PORT)
{
    localPORT = PORT;
}

void VoIPClient::SetRemoteHost(QHostAddress HOST)
{
    remoteHOST = HOST;
}

void VoIPClient::SetRemotePort(quint16 PORT)
{
    remotePORT = PORT;
}


P.S. Вызываю метод VoIPClient::StartConversation(), предварительно установив IP и порты.
  • Вопрос задан
  • 4987 просмотров
Пригласить эксперта
Ответы на вопрос 1
Тут смотрел про bind у client?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы