【Qt\C++】Qt实现简易对话程序

这是一个通过Qt实现的语音对话程序,我将通过几个步骤带你程序实现逻辑

设计思路:

1、使用QAudioInput进行音频输入;使用QAudioOutput进行音频输出
2、使用UDP进行音频数据传输
3、使用QTimer进行通话计时

头文件定义:

#include <QWidget>
#include <QUdpSocket>
#include <QAudioInput>
#include <QAudioOutput>
#include <QIODevice>
#include <QTimer>
#include <QTime>

namespace Ui {
class VoiceCall;
}

class VoiceCall : public QWidget
{
    Q_OBJECT

public:
    explicit VoiceCall(QWidget *parent = 0);
    ~VoiceCall();

private:
    //初始化音频
    void initAudio();

    //开始通话
    void startCall();

    //挂断通话
    void hungUp();

private slots:
    void on_btn_dial_clicked();

    void socketRead();

    void audioRead();

    void on_btn_hungUp_clicked();

    void timeOut();

private:
    Ui::VoiceCall *ui;
    //UDP
    QUdpSocket *m_pSocket;
    //音频输入
    QAudioInput *m_pAudioInput;
    //音频输出
    QAudioOutput *m_pAudioOutput;

    //音频输入IO
    QIODevice *m_pAudioInputIO;
    //音频输出IO
    QIODevice *m_pAudioOutputIO;

    //对方IP
    QHostAddress m_address;
    //对话端口
    int m_port;
    //通话计时
    QTime m_time;
    //通话计时定时器
    QTimer *m_pTimer;
};

创建UDP通信和初始化音频

VoiceCall::VoiceCall(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::VoiceCall)
{
    ui->setupUi(this);
    m_pSocket = new QUdpSocket(this);
    m_pSocket->bind(QHostAddress::Any, 8000);
    connect(m_pSocket, SIGNAL(readyRead()), this, SLOT(socketRead()));
    ui->btn_dial->setEnabled(true);
    m_pTimer = new QTimer(this);
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(timeOut()));
    initAudio();
}

VoiceCall::~VoiceCall()
{
    delete ui;
}

void VoiceCall::initAudio()
{
    //设置音频格式
    QAudioFormat format;
    format.setSampleRate(8000);
    format.setSampleSize(8);
    format.setSampleType(QAudioFormat::SignedInt);
    format.setChannelCount(1);
    format.setCodec("audio/pcm");
    format.setByteOrder(QAudioFormat::LittleEndian);
    //获取默认的输入设备
    QAudioDeviceInfo device = QAudioDeviceInfo::defaultInputDevice();
    //判断设备是否有效,如果无效 获取最近的有效设备
    if (!device.isFormatSupported(format))
    {
        format = device.nearestFormat(format);
    }
    //初始化输入
    m_pAudioInput = new QAudioInput(format, this);
    //初始化输出
    m_pAudioOutput = new QAudioOutput(format, this);
}

进行语音通话

void VoiceCall::on_btn_dial_clicked()
{
    QString address = ui->lineEdit_ipAddress->text();
    if (address.isEmpty())
    {
        QMessageBox::information(this, "提示", "IP地址不能空!");
        return;
    }
    else
    {
        m_pSocket->writeDatagram(QByteArray("call"), QHostAddress(address), 8000);
    }
}

结束语音通话

void VoiceCall::hungUp()
{
    ui->label_time->setText("");
    ui->label_user->setText("");
    m_pTimer->stop();
    m_pAudioInputIO->close();
    m_pAudioOutputIO->close();
    disconnect(m_pAudioInputIO, SIGNAL(readyRead()), this, SLOT(audioRead()));
    m_pAudioInput->stop();
    m_pAudioOutput->stop();
    ui->btn_dial->setEnabled(true);
    ui->btn_hungUp->setEnabled(false);
}

void VoiceCall::on_btn_hungUp_clicked()
{
    m_pSocket->writeDatagram(QByteArray("disConnect"), QHostAddress(m_address), m_port);
    hungUp();
}

开始通话以及音频数据读取

void VoiceCall::startCall()
{
    ui->btn_hungUp->setEnabled(true);
    ui->btn_dial->setEnabled(false);
    //对话已连接
    qDebug() << "对话已连接";
    //开始录音
    m_pAudioInputIO = m_pAudioInput->start();
    connect(m_pAudioInputIO, SIGNAL(readyRead()), this, SLOT(audioRead()));
    m_pAudioOutputIO = m_pAudioOutput->start();
    m_time = QTime(0, 0, 0);
    ui->label_time->show();
    ui->label_time->setText("通话时长:" + m_time.toString("hh:mm::ss"));
    ui->label_user->show();
    ui->label_user->setText("通话来自:" + m_address.toString().mid(7));
    m_pTimer->start(1000);
}

void VoiceCall::audioRead()
{
    QByteArray buffer;
    buffer = m_pAudioInputIO->readAll();
    //qDebug() << buffer.size();
    if (buffer.size() > 1280)
    {
        return;
    }
    buffer.insert(0, "audio");
    m_pSocket->writeDatagram(buffer, m_address, m_port);
}

UDP通信数据解析

void VoiceCall::socketRead()
{
    while (m_pSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(m_pSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        m_pSocket->readDatagram(datagram.data(), datagram.size(),
                                    &sender, &senderPort);
        if (datagram == "call")
        {
            if (QMessageBox::question(this, "提示", QString("来自%1的通话,是否接通?").arg(sender.toString().mid(7))) == QMessageBox::Yes)
            {
                m_pSocket->writeDatagram(QByteArray("connect"), sender, senderPort);
                //保存对话的IP
                m_address = sender;
                m_port = senderPort;
                startCall();
            }
            else
            {
                m_pSocket->writeDatagram(QByteArray("connectionDenied"), sender, senderPort);
            }
        }
        else if (datagram == "connect")
        {
            qDebug() << "对方已接通";
            //保存对话的IP
            m_address = sender;
            m_port = senderPort;
            startCall();
        }
        else if (datagram == "connectionDenied")
        {
            //对方拒绝通话
            QMessageBox::information(this, "提示", "对方拒绝通话");
        }
        else if (datagram == "disConnect")
        {
            //挂断通话
            hungUp();
            QMessageBox::information(this, "提示", "对方已经挂断通话");
        }
        else
        {
            //接收到通话数据
            if (datagram.startsWith("audio"))
            {
                //说明是接受到了录音数据
                m_pAudioOutputIO->write(datagram.mid(QByteArray("audio").size()));
            }
        }
    }
}

通话计时

void VoiceCall::timeOut()
{
    m_time = m_time.addSecs(1);
    ui->label_time->setText("通话时长:" + m_time.toString("hh:mm::ss"));
}

源代码下载链接:
https://download.csdn.net/download/Mrack/89079568

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mrack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值