Ох, здравствуйте, товарищи. Пишу курсовую работу: голосовая связь по 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 и порты.