Russian Qt Forum
Март 28, 2024, 14:58
Добро пожаловать,
Гость
. Пожалуйста,
войдите
или
зарегистрируйтесь
.
Вам не пришло
письмо с кодом активации?
1 час
1 день
1 неделя
1 месяц
Навсегда
Войти
Начало
Форум
WIKI (Вики)
FAQ
Помощь
Поиск
Войти
Регистрация
Russian Qt Forum
>
Forum
>
Qt
>
Работа с сетью
>
[Решено] QUdpSocket::readyRead()
Страниц: [
1
]
Вниз
« предыдущая тема
следующая тема »
Печать
Автор
Тема: [Решено] QUdpSocket::readyRead() (Прочитано 15743 раз)
ProGOLD
Гость
[Решено] QUdpSocket::readyRead()
«
:
Январь 16, 2012, 01:29 »
Здравствуйте, люди добрые. Уже месяц мучаюсь с одной проблемой.
Пишу курсовую работу на Qt: голосовая связь по протоколу UDP. Разумеется, клиенты взаимодействуют peer-to-peer, а для захвата и воспроизведения звука используются
QAudioInput
и
QAudioOutput
.
Сначала стал изобретать одноколесный велосипед с QBuffer. Потом понял, что он тут вообще не нужен, и создал два класса для отправки и получения звука по UDP:
AudioTransmitter
и
AudioReciever
, соответственно. Эти классы являются потомками QIODevice и передаются в качестве параметров методу start(QIODevice*) классов
QAudioInput
и
QAudioOutput
, соответственно. Отправка звука работает на ура (это подтверждает сниффер), а вот прием работает только на одной стороне. Причем всегда звук проигрывается на том клиенте, который "стартовал" позже. В логе видно, что после старта
QAudioOutput
4 раза вызывается метод
qint64 AudioReciever::readData(char*, qint64)
, который возвращает -1 (потому что второй клиент еще ничего не присылал). И больше этот метод не вызывается. Я сделал единственный логичный вывод:
QUdpSocket
не генерирует сигнал
readyRead()
.
В документации по QUdpSocket есть одна любопытная фраза:
An incoming datagram should be read when you receive the readyRead() signal, otherwise this signal will not be emitted for the next datagram.
Это единственная зацепка в документации, но не похоже, что она имеет место в моем случае, т.к. readyRead всегда обрабатывается.
Любопытно следующее: если в метод AudioReciever::readData добавить цикл while (socket.hasPendingDatagram()), звук проигрывается с обеих сторон, но жутко лагает (видимо, часть пакетов просто пропадает в этом случае).
В общем, не знаю, что делать и расчитываю на помощь специалистов. Два основных исходных файла я запостил ниже, а весь проект в прикрепленном архиве. Заранее спасибо.
Код:
#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);
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);
bool Bind(void);
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
bool isSequential(void) const;
bool seek(qint64 pos);
void Clear(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)
{
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)
{
localHOST = localHost;
localPORT = localPort;
remoteHOST = remoteHost;
remotePORT = remotePort;
}
bool AudioReciever::Bind(void)
{
connect(&socket, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
return socket.bind(localHOST, localPORT, QUdpSocket::DontShareAddress);
//qDebug() << "Successfully binded to" << localHOST.toString() << ":" << localPORT << ".";
}
qint64 AudioReciever::readData(char *data, qint64 maxlen)
{
qint64 readBytes = 0;
// for (unsigned int i=0; i<2; i++)
// if (socket.hasPendingDatagrams())
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;
}
void AudioReciever::Clear(void)
{
// char * data;
// qint64 size = 320;
// while (socket.hasPendingDatagrams())
// socket.readDatagram(data,size);
}
Код:
#include <QThread>
#include "audio.h"
class VoIPClient : public QThread
{
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);
protected:
void run(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);
volatile bool stopped;
signals:
};
VoIPClient::VoIPClient(QObject *parent) : QThread(parent)
{
stopped = false;
}
VoIPClient::~VoIPClient(void)
{
}
void VoIPClient::run(void)
{
QAudioFormat format = GetStreamAudioFormat();
audio_input = new QAudioInput(format);
audio_output = new QAudioOutput(format);
transmitter = new AudioTransmitter(localHOST, localPORT, remoteHOST, remotePORT);
reciever = new AudioReciever(localHOST, localPORT, remoteHOST, remotePORT);
//connect(audio_output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(ResumePlaying(QAudio::State)));
connect(reciever, SIGNAL(readyRead()), this, SLOT(ResumePlaying()));
reciever->Bind();
transmitter->open(QIODevice::WriteOnly | QIODevice::Truncate);
reciever->open(QIODevice::ReadOnly);
audio_output->start(reciever);
// reciever->Clear();
audio_input->start(transmitter);
qDebug() << "Started conversation with" << remoteHOST.toString() << ".";
exec();
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::Call(void)
{
start();
}
void VoIPClient::FinishCall(void)
{
exit(0);
}
void VoIPClient::StartConversation(void)
{
}
void VoIPClient::StopConversation(void)
{
}
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;
}
«
Последнее редактирование: Январь 17, 2012, 17:24 от ProGOLD
»
Записан
popper
Гость
Re: QUdpSocket readyRead
«
Ответ #1 :
Январь 16, 2012, 15:25 »
Ориентируясь на пример из документации по QUDPSocket, предлагаю попробовать так:
Код:
AudioReciever::Bind()
{
connect(&socket, SIGNAL(readyRead()), this, SLOT(myPrivateReadSocket()));
...
}
AudioReciever::myPrivateReadSocket()
{
// QByteArray m_datagram is private buffer
while (udpSocket->hasPendingDatagrams()) {
QByteArray tmp;
tmp.resize(udpSocket->pendingDatagramSize());
socket.readDatagram(tmp.data(), tmp.size());
m_datagram.append(tmp);
}
emit readyRead();
}
qint64 AudioReciever::readData(char *data, qint64 maxlen)
{
qint64 readBytes = qMin(m_datagram.size(), maxlen);
// copy readBytes bytes from m_datagram to data and remove this bytes from m_datagram
return readBytes;
}
Записан
ProGOLD
Гость
Re: QUdpSocket readyRead
«
Ответ #2 :
Январь 16, 2012, 18:22 »
Внес следующие изменения:
Код:
bool AudioReciever::Bind(void)
{
connect(&socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
return socket.bind(localHOST, localPORT, QUdpSocket::DontShareAddress);
}
void AudioReciever::readPendingDatagrams(void)
{
while (socket.hasPendingDatagrams())
{
QByteArray tmp;
tmp.resize(socket.pendingDatagramSize());
socket.readDatagram(tmp.data(), tmp.size());
m_datagram.append(tmp);
}
emit readyRead();
}
qint64 AudioReciever::readData(char *data, qint64 maxlen)
{
qint64 readBytes = qMin(qint64(m_datagram.size()), maxlen);
if (readBytes > 0)
{
QByteArray tmp = m_datagram.left(readBytes);
m_datagram.remove(0,readBytes);
data = new char[readBytes];
char * tmp_ptr = tmp.data();
for (unsigned int i = 0; i < readBytes; i++)
data[i] = tmp_ptr[i];
qDebug() << "Recieved " << readBytes << " bytes.";
}
return readBytes;
}
Увы, проблема не решилась. Теперь с обеих сторон слышен треск и ничего больше. Может, я с памятью работаю неправильно?
Записан
andrew.k
Гость
Re: QUdpSocket readyRead
«
Ответ #3 :
Январь 16, 2012, 18:38 »
мне-кажется ты скорее неправильно работаешь с qsound*
ты его по приходу каждого куска растартуешь. потому и треск.
сам не пользовался, поэтому подробнее не скажу.
Записан
ProGOLD
Гость
Re: QUdpSocket readyRead
«
Ответ #4 :
Январь 16, 2012, 19:00 »
Я его перезапускаю только если он уже остановился.
Код:
void VoIPClient::ResumePlaying(void)
{
if (audio_output->state() != QAudio::ActiveState)
{
audio_output->stop();
audio_output->start(reciever);
}
}
Записан
popper
Гость
Re: QUdpSocket readyRead
«
Ответ #5 :
Январь 16, 2012, 19:48 »
Пока еще предлагаю поиграть с QAudioFormat::LittleEndian и QAudioFormat::BigEndian.
И вот этот код мне не нравится:
Код:
connect(reciever, SIGNAL(readyRead()), this, SLOT(ResumePlaying()));
Позже посмотрю еще внимательнее
Записан
ProGOLD
Гость
Re: QUdpSocket readyRead
«
Ответ #6 :
Январь 16, 2012, 20:38 »
Цитировать
Пока еще предлагаю поиграть с QAudioFormat::LittleEndian и QAudioFormat::BigEndian.
Безрезультатно.
Цитировать
И вот этот код мне не нравится:
Код:
connect(reciever, SIGNAL(readyRead()), this, SLOT(ResumePlaying()));
Без него на клиенте, который был запущен первым, звук воспроизводиться не будет.
Я почистил проект от лишнего.
Код:
#include <QObject>
#include <QtGlobal>
#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:
AudioTransmitter(quint16 localPort, QHostAddress remoteHost, quint16 remotePort);
qint64 writeData(const char *data, qint64 len);
qint64 readData(char *data, qint64 maxlen);
private:
QUdpSocket socket;
quint16 localPORT;
QHostAddress remoteHOST;
quint16 remotePORT;
};
// Class produces a device to recieve audio from the network.
class AudioReciever : public QIODevice
{
Q_OBJECT
public:
AudioReciever(quint16 localPort, QHostAddress remoteHost, quint16 remotePort);
bool Bind(void);
bool isSequential(void) const;
bool seek(qint64 pos);
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
private:
QUdpSocket socket;
quint16 localPORT;
QHostAddress remoteHOST;
quint16 remotePORT;
QByteArray buffer;
private slots:
void readPendingDatagrams(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(quint16 localPort, QHostAddress remoteHost, quint16 remotePort)
{
localPORT = localPort;
remoteHOST = remoteHost;
remotePORT = remotePort;
}
qint64 AudioTransmitter::writeData(const char *data, qint64 len)
{
qint64 writtenBytes = socket.writeDatagram(data, len, remoteHOST, remotePORT);
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(quint16 localPort, QHostAddress remoteHost, quint16 remotePort)
{
localPORT = localPort;
remoteHOST = remoteHost;
remotePORT = remotePort;
}
bool AudioReciever::Bind(void)
{
connect(&socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
return socket.bind(QHostAddress::Any, localPORT, QUdpSocket::DontShareAddress);
}
bool AudioReciever::isSequential(void) const
{
return true;
}
bool AudioReciever::seek(qint64 pos)
{
Q_UNUSED(pos);
return false;
}
void AudioReciever::readPendingDatagrams(void)
{
while (socket.hasPendingDatagrams())
{
QByteArray tmp;
tmp.resize(socket.pendingDatagramSize());
socket.readDatagram(tmp.data(), tmp.size());
buffer.append(tmp);
}
emit readyRead();
}
qint64 AudioReciever::readData(char *data, qint64 maxlen)
{
qint64 readBytes = qMin(qint64(buffer.size()), maxlen);
if (readBytes > 0)
{
QByteArray tmp = buffer.left(readBytes);
buffer.remove(0,readBytes);
data = new char[readBytes];
char * tmp_ptr = tmp.data();
for (unsigned int i = 0; i < readBytes; i++)
data[i] = tmp_ptr[i];
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;
}
Код:
#include <QThread>
class VoIPClient : public QThread
{
Q_OBJECT
public:
explicit VoIPClient(QObject *parent = 0);
~VoIPClient(void);
void SetLocalPort(quint16 PORT);
void SetRemoteHost(QHostAddress HOST);
void SetRemotePort(quint16 PORT);
public slots:
void Call(void);
void FinishCall(void);
void ResumePlaying(void);
void ResumePlaying(QAudio::State);
protected:
void run(void);
private:
QHostAddress remoteHOST;
quint16 localPORT;
quint16 remotePORT;
QAudioInput * audio_input;
QAudioOutput * audio_output;
AudioTransmitter * transmitter;
AudioReciever * reciever;
};
VoIPClient::VoIPClient(QObject *parent) : QThread(parent)
{
}
VoIPClient::~VoIPClient(void)
{
}
void VoIPClient::run(void)
{
QAudioFormat format = GetStreamAudioFormat();
audio_input = new QAudioInput(format);
audio_output = new QAudioOutput(format);
transmitter = new AudioTransmitter(localPORT, remoteHOST, remotePORT);
reciever = new AudioReciever(localPORT, remoteHOST, remotePORT);
//connect(audio_output, SIGNAL(stateChanged(QAudio::State)), this, SLOT(ResumePlaying(QAudio::State)));
connect(reciever, SIGNAL(readyRead()), this, SLOT(ResumePlaying()));
reciever->Bind();
transmitter->open(QIODevice::WriteOnly | QIODevice::Truncate);
reciever->open(QIODevice::ReadOnly);
audio_output->start(reciever);
audio_input->start(transmitter);
qDebug() << "Started conversation with" << remoteHOST.toString() << ".";
exec();
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::Call(void)
{
start();
}
void VoIPClient::FinishCall(void)
{
exit(0);
}
void VoIPClient::ResumePlaying(void)
{
if (audio_output->state() != QAudio::ActiveState)
{
audio_output->start(reciever);
}
}
void VoIPClient::ResumePlaying(QAudio::State state)
{
if (state != QAudio::ActiveState)
{
audio_output->start(reciever);
}
}
void VoIPClient::SetLocalPort(quint16 PORT)
{
localPORT = PORT;
}
void VoIPClient::SetRemoteHost(QHostAddress HOST)
{
remoteHOST = HOST;
}
void VoIPClient::SetRemotePort(quint16 PORT)
{
remotePORT = PORT;
}
Записан
ProGOLD
Гость
Re: QUdpSocket readyRead
«
Ответ #7 :
Январь 16, 2012, 20:46 »
QUdpSocket принимает корректный массив char*, это было проверено ранее. Следовательно, порча происходит дальше. Но дебаггер в Qt Creator странно показывает данные при отладке, и я не могу понять, где именно данные портятся.
Записан
popper
Гость
Re: QUdpSocket readyRead
«
Ответ #8 :
Январь 17, 2012, 10:42 »
Мне кажется, что класс AudioTransmitter вообще не нужен, т.к. QUDPSocket наследуется от QIODevice и QAudioInput может с ним напрямую работать.
Может быть лагание звука связано с пакетной передачей данных?
Попробуй сохранить принятые данные в файл и проиграть их отдельно.
Записан
ProGOLD
Гость
Re: QUdpSocket readyRead
«
Ответ #9 :
Январь 17, 2012, 13:43 »
При записи в QFile все нормально. Следовательно, этот блок (и весь слот readPendingDatagrams()) работает правильно:
Код:
QMutexLocker locker(&mutex);
QByteArray tmp = buffer.left(readBytes);
buffer.remove(0,readBytes);
locker.unlock();
Как видите, даже синхронизация буфера между потоками не помогает.
Код:
AudioReciever::AudioReciever(quint16 localPort, QHostAddress remoteHost, quint16 remotePort)
{
localPORT = localPort;
remoteHOST = remoteHost;
remotePORT = remotePort;
dest = new QFile("C:\\test.raw");
dest->open(QIODevice::WriteOnly | QIODevice::Truncate);
}
AudioReciever::~AudioReciever(void)
{
dest->close();
delete dest;
}
bool AudioReciever::Bind(void)
{
connect(&socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
return socket.bind(QHostAddress::Any, localPORT, QUdpSocket::DontShareAddress);
}
bool AudioReciever::isSequential(void) const
{
return true;
}
bool AudioReciever::seek(qint64 pos)
{
Q_UNUSED(pos);
return false;
}
void AudioReciever::readPendingDatagrams(void)
{
while (socket.hasPendingDatagrams())
{
QByteArray tmp;
tmp.resize(socket.pendingDatagramSize());
socket.readDatagram(tmp.data(), tmp.size());
QMutexLocker locker(&mutex);
buffer.append(tmp);
locker.unlock();
qDebug() << "Recieved " << tmp.size() << " bytes.";
emit readyRead();
}
}
qint64 AudioReciever::readData(char *data, qint64 maxlen)
{
qint64 readBytes = qMin(qint64(buffer.size()), maxlen);
if (readBytes > 0)
{
QMutexLocker locker(&mutex);
QByteArray tmp = buffer.left(readBytes);
buffer.remove(0,readBytes);
locker.unlock();
data = new char[readBytes];
qstrncpy(data, tmp.data(), readBytes);
dest->write(tmp.data(), tmp.size());
qDebug() << "Returned from AudioReciever::readData():" << readBytes;
}
return readBytes;
}
qint64 AudioReciever::writeData(const char *data, qint64 len)
{
Q_UNUSED(data);
Q_UNUSED(len);
qDebug() << "IOError: device is read-only.";
return 0;
}
Записан
popper
Гость
Re: QUdpSocket readyRead
«
Ответ #10 :
Январь 17, 2012, 14:47 »
Еще 3 рекомендации:
1. В AudioReceiver переопределить метод QIODevice::bytesAvailable ()
2. Завести в потоке слот на сигнал void QAudioOutput::stateChanged ( QAudio::State state ) [signal] и вывести в дебаг информацию
3. Пройтись по исходникам QAudioOutput и посмотреть, как он работает с объектом QIODevice
Проверь, может ли в твоем коде
Код:
void VoIPClient::ResumePlaying(void)
{
if (audio_output->state() != QAudio::ActiveState)
{
audio_output->start(reciever);
}
}
быть такое, что пока данные по UDP обрабатывались в AudioReceiver, QAudioOutput уже закончил проигрывать имеющиеся данные. Тогда
Код:
QAudio::ActiveState == QAudio::IdleState
В этом случае, по идее, при получении сигнала readyRead() QAudioOutput сам должен возобновлять проигрывание звука.
Записан
ProGOLD
Гость
Re: QUdpSocket readyRead
«
Ответ #11 :
Январь 17, 2012, 17:21 »
Спасибо за помощь. Нашел подсказку тут:
http://stackoverflow.com/a/3438566
.
Нужно было вызывать именно
QIODevice * QAudioOutput.start(void)
, теперь все работает, хотя и немного лагает.
В погоне за симметрией я модифицировал и без того работавший AudioTransmiter. Конечный код выглядит так:
Код:
#include <QObject>
#include <QIODevice>
#include <QUdpSocket>
#include <QHostAddress>
#include <QAudioInput>
#include <QAudioOutput>
// Function returns constant audio format of all audio streams.
QAudioFormat GetStreamAudioFormat(void);
// Class produces a device to capture and send audio over the network.
class AudioTransmitter : public QObject
{
Q_OBJECT
public:
AudioTransmitter(quint16 localPort, QHostAddress remoteHost, quint16 remotePort);
void Start(void);
void Stop(void);
private:
QUdpSocket socket;
QAudioInput * audio_input;
QIODevice * audio_device;
quint16 localPORT;
QHostAddress remoteHOST;
quint16 remotePORT;
const qint64 maxsize;
private slots:
void sendDatagrams(void);
};
// Class produces a device to recieve audio from the network and play it.
class AudioReciever : public QObject
{
Q_OBJECT
public:
AudioReciever(quint16 localPort, QHostAddress remoteHost, quint16 remotePort);
bool Start(void);
void Stop(void);
private:
QUdpSocket socket;
QAudioOutput * audio_output;
QIODevice * audio_device;
quint16 localPORT;
QHostAddress remoteHOST;
quint16 remotePORT;
private slots:
void readPendingDatagrams(void);
};
QAudioFormat GetStreamAudioFormat(void)
{
QAudioFormat format;
format.setSampleRate(44100);
format.setChannels(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::UnSignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!info.isFormatSupported(format))
format = info.nearestFormat(format);
return format;
}
//////////////////////////////////
// AudioTransmitter Class
//////////////////////////////////
AudioTransmitter::AudioTransmitter(quint16 localPort, QHostAddress remoteHost, quint16 remotePort)
: maxsize(8192)
{
localPORT = localPort;
remoteHOST = remoteHost;
remotePORT = remotePort;
}
void AudioTransmitter::Start(void)
{
audio_input = new QAudioInput(GetStreamAudioFormat());
audio_device = audio_input->start();
connect(audio_device, SIGNAL(readyRead()), this, SLOT(sendDatagrams()));
}
void AudioTransmitter::Stop(void)
{
audio_input->stop();
delete audio_input;
socket.close();
disconnect(audio_device, SIGNAL(readyRead()), this, SLOT(sendDatagrams()));
}
void AudioTransmitter::sendDatagrams(void)
{
QByteArray tmp = audio_device->read(maxsize);
socket.writeDatagram(tmp.data(), tmp.size(), remoteHOST, remotePORT);
}
//////////////////////////////////
// AudioReciever Class
//////////////////////////////////
AudioReciever::AudioReciever(quint16 localPort, QHostAddress remoteHost, quint16 remotePort)
{
localPORT = localPort;
remoteHOST = remoteHost;
remotePORT = remotePort;
}
bool AudioReciever::Start(void)
{
audio_output = new QAudioOutput(GetStreamAudioFormat());
audio_device = audio_output->start();
connect(&socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
return socket.bind(QHostAddress::Any, localPORT, QUdpSocket::DontShareAddress);
}
void AudioReciever::Stop(void)
{
audio_output->stop();
delete audio_output;
socket.close();
disconnect(&socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
void AudioReciever::readPendingDatagrams(void)
{
while (socket.hasPendingDatagrams())
{
qint64 size = socket.pendingDatagramSize();
char * data = new char[size];
socket.readDatagram(data, size);
audio_device->write(data, size);
}
}
Код:
#include <QThread>
class VoIPClient : public QThread
{
Q_OBJECT
public:
explicit VoIPClient(QObject *parent = 0);
void SetLocalPort(quint16 PORT);
void SetRemoteHost(QHostAddress HOST);
void SetRemotePort(quint16 PORT);
public slots:
void Call(void);
void FinishCall(void);
protected:
void run(void);
private:
AudioTransmitter * transmitter;
AudioReciever * reciever;
QHostAddress remoteHOST;
quint16 localPORT;
quint16 remotePORT;
};
VoIPClient::VoIPClient(QObject *parent) : QThread(parent)
{
}
void VoIPClient::run(void)
{
transmitter = new AudioTransmitter(localPORT, remoteHOST, remotePORT);
reciever = new AudioReciever(localPORT, remoteHOST, remotePORT);
reciever->Start();
transmitter->Start();
exec();
transmitter->Stop();
reciever->Stop();
delete transmitter;
delete reciever;
}
void VoIPClient::Call(void)
{
start();
}
void VoIPClient::FinishCall(void)
{
exit(0);
}
void VoIPClient::SetLocalPort(quint16 PORT)
{
localPORT = PORT;
}
void VoIPClient::SetRemoteHost(QHostAddress HOST)
{
remoteHOST = HOST;
}
void VoIPClient::SetRemotePort(quint16 PORT)
{
remotePORT = PORT;
}
Может быть, кому-то мой проект (пока не доделанный) окажется полезным. Посему добавляю к посту вложение.
Записан
Fregloin
Супер
Offline
Сообщений: 1025
Re: [Решено] QUdpSocket::readyRead()
«
Ответ #12 :
Январь 18, 2012, 12:36 »
еще советовал бы сделать внутренний буфер на несколько секунд, в который клеять принятые данные, возможно лаг уменьшится...
Записан
popper
Гость
Re: [Решено] QUdpSocket::readyRead()
«
Ответ #13 :
Январь 18, 2012, 12:55 »
Еще можно попробовать уменьшить частоту семплирования до минимального поддерживаемого значения
Записан
Страниц: [
1
]
Вверх
Печать
« предыдущая тема
следующая тема »
Перейти в:
Пожалуйста, выберите назначение:
-----------------------------
Qt
-----------------------------
=> Вопросы новичков
=> Уроки и статьи
=> Установка, сборка, отладка, тестирование
=> Общие вопросы
=> Пользовательский интерфейс (GUI)
=> Qt Quick
=> Model-View (MV)
=> Базы данных
=> Работа с сетью
=> Многопоточное программирование, процессы
=> Мультимедиа
=> 2D и 3D графика
=> OpenGL
=> Печать
=> Интернационализация, локализация
=> QSS
=> XML
=> Qt Script, QtWebKit
=> ActiveX
=> Qt Embedded
=> Дополнительные компоненты
=> Кладовая готовых решений
=> Вклад сообщества в Qt
=> Qt-инструментарий
-----------------------------
Программирование
-----------------------------
=> Общий
=> С/C++
=> Python
=> Алгоритмы
=> Базы данных
=> Разработка игр
-----------------------------
Компиляторы и платформы
-----------------------------
=> Linux
=> Windows
=> Mac OS X
=> Компиляторы
===> Visual C++
-----------------------------
Разное
-----------------------------
=> Новости
===> Новости Qt сообщества
===> Новости IT сферы
=> Говорилка
=> Юмор
=> Объявления
Загружается...