一、环境介绍
【资料图】
QT版本:
操作系统: Android、ubuntu、windows 都测试OK。
二、功能介绍
两台设备之间实现语音对讲功能。类似于QQ、微信语音电话效果。
采用QAudioInput获取声卡输出,QAudioOutpu用于输出数据到声卡。
音频数据采用TCP网络方式双向传输。
(1)对讲APP服务器端: 服务器收到客户端的数据就播放,同时采集声卡数据发送给客户端。
(2) 对讲APP客户端:客户端收到服务器的数据就播放,同时采集声卡数据发送给服务器。
对讲APP服务器端
对讲APP客户端
三、音频客户端: 核心代码
文件代码:
#ifndef AUDIOINPUTOUT_H#define AUDIOINPUTOUT_H#include #include #include #include //获取计算机网络信息#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //这五个是QT处理音频的库#include #include #include #include #define AUDIO_SERVER_IP ""#define AUDIO_SERVER_PROT 8888//用于连接服务器,实现语音对讲功能class AudioInputOutput : public QObject{ Q_OBJECTpublic: QTcpSocket *LocalTcpClientSocket; AudioInputOutput(QObject* parent=nullptr):QObject(parent) { LocalTcpClientSocket=nullptr; audio_in=nullptr; audio_out=nullptr; } void TCP_ConnectServer(QString Ipaddr, quint16 prot); void Audio_in_Init(); void Audio_Out_Init(); QAudioInput *audio_in; QAudioOutput *audio_out; QIODevice* audio_streamIn; QIODevice* audio_out_streamIn;public slots: void LocalTcpClientConnectedSlot(); void LocalTcpClientDisconnectedSlot(); void LocalTcpClientReadDtatSlot(); void run(); void handleStateChanged_input(QAudio::State newState); void audio_ReadyRead(); void stop_connect();signals: void LogSend(QString text);};#endif // AUDIOINPUTOUT_H
文件代码:
#include ""//创建客户端,连接至服务器void AudioInputOutput::TCP_ConnectServer(QString Ipaddr,quint16 prot){ /* 设置服务器IP地址*/ QHostAddress FarServerAddr(Ipaddr); if(LocalTcpClientSocket==nullptr) { /*1. 创建本地客户端TCP套接字*/ LocalTcpClientSocket = new QTcpSocket; /*2. 连接客户端的信号槽*/ connect(LocalTcpClientSocket,SIGNAL(connected()),this,SLOT(LocalTcpClientConnectedSlot())); connect(LocalTcpClientSocket,SIGNAL(disconnected()),this,SLOT(LocalTcpClientDisconnectedSlot())); connect(LocalTcpClientSocket,SIGNAL(readyRead()),this,SLOT(LocalTcpClientReadDtatSlot())); } /*3. 尝试连接服务器主机*/ LocalTcpClientSocket->connectToHost(FarServerAddr,prot);}//开始执行程序void AudioInputOutput::run(){ TCP_ConnectServer(AUDIO_SERVER_IP,AUDIO_SERVER_PROT); Audio_in_Init(); Audio_Out_Init();}//客户端模式:响应连接上服务器之后的操作void AudioInputOutput::LocalTcpClientConnectedSlot(){ LocalTcpClientSocket->write("device connect server."); LogSend("连接上服务器.
");}//客户端模式:断开服务器void AudioInputOutput::LocalTcpClientDisconnectedSlot(){ //停止音频输入输出 audio_in->stop(); audio_out->stop(); LogSend("服务器断开.
");}//客户端模式:读取服务器发过来的数据void AudioInputOutput::LocalTcpClientReadDtatSlot(){ QByteArray array=LocalTcpClientSocket->readAll(); audio_out_streamIn->write(array);}//音频输出初始化void AudioInputOutput::Audio_Out_Init(){ QAudioFormat auido_out_format; //设置录音的格式 auido_out_(44100); //设置采样率以对赫兹采样。 以秒为单位,每秒采集多少声音数据的频率. auido_out_(1); //将通道数设置为通道。 auido_out_(16); /*将样本大小设置为指定的sampleSize(以位为单位)通常为8或16,但是某些系统可能支持更大的样本量。*/ auido_out_("audio/pcm"); //设置编码格式 auido_out_(QAudioFormat::LittleEndian); //样本是小端字节顺序 auido_out_(QAudioFormat::SignedInt); //样本类型 QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if(audio_out) { delete audio_out; audio_out=nullptr; } audio_out = new QAudioOutput(auido_out_format); audio_out_streamIn=audio_out->start();}// 音频输入初始化void AudioInputOutput::Audio_in_Init(){ QString text; QAudioFormat auido_input_format; //设置录音的格式 auido_input_(44100); //设置采样率以对赫兹采样。 以秒为单位,每秒采集多少声音数据的频率. auido_input_(1); //将通道数设置为通道。 auido_input_(16); /*将样本大小设置为指定的sampleSize(以位为单位)通常为8或16,但是某些系统可能支持更大的样本量。*/ auido_input_("audio/pcm"); //设置编码格式 auido_input_(QAudioFormat::LittleEndian); //样本是小端字节顺序 auido_input_(QAudioFormat::SignedInt); //样本类型 //选择设备作为输入源 QAudioDeviceInfo info =QAudioDeviceInfo::defaultInputDevice(); emit LogSend(tr("当前的录音设备的名字:%1
").arg(())); //判断输入的格式是否支持,如果不支持就使用系统支持的默认格式 if(!(auido_input_format)) { emit LogSend("返回与系统支持的提供的设置最接近的QAudioFormat
"); auido_input_format=(auido_input_format); /* * 返回与系统支持的提供的设置最接近的QAudioFormat。 这些设置由所使用的平台/音频插件提供。 它们还取决于所使用的QAudio :: Mode。 */ } //当前设备支持的编码 emit LogSend("当前设备支持的编码格式:
"); QStringList list=(); for(int i=0;istart(); //开始音频采集 //关联音频读数据信号 connect(audio_streamIn,SIGNAL(readyRead()),this,SLOT(audio_ReadyRead()),Qt::QueuedConnection);}//有音频信号可以读void AudioInputOutput::audio_ReadyRead(){ QByteArray byte=audio_streamIn->readAll(); //判断服务器是否处于连接状态 if(LocalTcpClientSocket->socketDescriptor()!=-1) { LocalTcpClientSocket->write(byte); }}//录音状态void AudioInputOutput::handleStateChanged_input(QAudio::State newState){ switch (newState) { case QAudio::StoppedState: if (audio_in->error() != QAudio::NoError) { // Error handling qDebug()<<"录音出现错误.
"; } else { // Finished recording qDebug()<<"完成录音
"; } break; case QAudio::ActiveState: // Started recording - read from IO device qDebug()<<"开始从IO设备读取PCM声音数据.
"; break; default: // ... other cases as appropriate break; }}//停止连接void AudioInputOutput::stop_connect(){ //判断服务器是否处于连接状态 if(LocalTcpClientSocket->socketDescriptor()!=-1) { //断开服务器连接 LocalTcpClientSocket->disconnectFromHost(); //停止音频输入输出 audio_in->stop(); audio_out->stop(); }}
【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】
点击这里:
#ifndef RECVSERVERCMD_H#define RECVSERVERCMD_H#include #include #include #include //获取计算机网络信息#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //这五个是QT处理音频的库#include #include #include #include #include #define RECV_SERVER_CMD_IP ""#define RECV_SERVER_CMD_PROT 6666//用于连接服务器,接收服务器下发的命令class RecvServerCmd : public QObject{ Q_OBJECTpublic: QTcpSocket *LocalTcpClientSocket; QTimer *timer_check_connect; RecvServerCmd(QObject* parent=nullptr):QObject(parent){LocalTcpClientSocket=nullptr;} void TCP_ConnectServer(QString Ipaddr, quint16 prot);public slots: void LocalTcpClientConnectedSlot(); void LocalTcpClientDisconnectedSlot(); void LocalTcpClientReadDtatSlot(); void run(); void check_connect();signals: void LogSend(QString text);};#endif // RECVSERVERCMD_H
#include ""//创建客户端,连接至服务器void RecvServerCmd::TCP_ConnectServer(QString Ipaddr,quint16 prot){ if(LocalTcpClientSocket==nullptr) { /*1. 创建本地客户端TCP套接字*/ LocalTcpClientSocket = new QTcpSocket; /*2. 设置服务器IP地址*/ QHostAddress FarServerAddr(Ipaddr); /*3. 连接客户端的信号槽*/ connect(LocalTcpClientSocket,SIGNAL(connected()),this,SLOT(LocalTcpClientConnectedSlot())); connect(LocalTcpClientSocket,SIGNAL(disconnected()),this,SLOT(LocalTcpClientDisconnectedSlot())); connect(LocalTcpClientSocket,SIGNAL(readyRead()),this,SLOT(LocalTcpClientReadDtatSlot())); /*4. 尝试连接服务器主机*/ LocalTcpClientSocket->connectToHost(FarServerAddr,prot); /*5. 检测服务器是否断开,并发送心跳包*/ timer_check_connect=new QTimer; connect(timer_check_connect,SIGNAL(timeout()),this,SLOT(check_connect())); timer_check_connect->start(1000*30); }}//开始执行程序void RecvServerCmd::run(){ TCP_ConnectServer(RECV_SERVER_CMD_IP,RECV_SERVER_CMD_PROT);}//客户端模式:响应连接上服务器之后的操作void RecvServerCmd::LocalTcpClientConnectedSlot(){ LocalTcpClientSocket->write("device connect server."); LogSend("命令长连接:连接上服务器.
");}//客户端模式:断开服务器void RecvServerCmd::LocalTcpClientDisconnectedSlot(){ LogSend("命令长连接:服务器断开.
");}//客户端模式:读取服务器发过来的数据void RecvServerCmd::LocalTcpClientReadDtatSlot(){ QByteArray array=LocalTcpClientSocket->readAll(); qDebug()<<"服务器下发的命令:"socketDescriptor()==-1) { /*4. 尝试连接服务器主机*/ LocalTcpClientSocket->connectToHost(QHostAddress(RECV_SERVER_CMD_IP),RECV_SERVER_CMD_PROT); } else { LocalTcpClientSocket->write("device connect ok."); }}
四、音频服务器端: 核心代码
码代码:
#include ""#include "ui_"Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget){ ui->setupUi(this); audio_in=nullptr; audio_out=nullptr; audio_streamIn=nullptr; audio_out_streamIn=nullptr; QListlist = QNetworkInterface::allAddresses(); for(int i=0;icomboBox->addItem(()); } }}Widget::~Widget(){ delete ui;}//服务器模式:创建服务器void Widget::Create_Server(){ /*1. 实例化服务器*/ LocalTcpServer= new QTcpServer; /*2. 设置监听的端口和IP地址*/ QHostAddress addr(ui->comboBox->currentText()); LocalTcpServer->listen(addr,8888); /*3. 关联连接信号,检测是否有新的客户端连接*/ connect(LocalTcpServer,SIGNAL(newConnection()),this,SLOT(NewTcpConnection()));}//服务器模式:响应新连接的客户端void Widget::NewTcpConnection(){ /*创建本地服务器套接字*/ QTcpSocket *ServerSocket=LocalTcpServer->nextPendingConnection(); /*关联可读信号*/ connect(ServerSocket,SIGNAL(readyRead()),this,SLOT(ReadTcpClientData())); /*关联断开信号*/ connect(ServerSocket,SIGNAL(disconnected()),this,SLOT(TcpClientDisconnected())); (ServerSocket);//添加到列表 //显示已经连接的客户端 ui->ClientComboBoxList->clear(); for(int i=0;i<();i++) { QString info=(i)->peerAddress().toString(); info+=":"; info+=QString::number((i)->peerPort()); ui->ClientComboBoxList->addItem(info); }}//服务器模式:响应断开的客户端void Widget::TcpClientDisconnected(){ for(int i=0;i<();i++) { //取出地址列表中的一个客户端地址 QTcpSocket *item = (i); //判断该客户端是否已经断开 if(item->socketDescriptor()==-1) { (i); } } //显示已经连接的客户端 ui->ClientComboBoxList->clear(); for(int i=0;i<();i++) { QString info=(i)->peerAddress().toString(); info+=":"; info+=QString::number((i)->peerPort()); ui->ClientComboBoxList->addItem(info); }}//服务器模式:读数据void Widget::ReadTcpClientData(){ for(int i=0;i<();i++) { if(!(i)->atEnd()) { QByteArray array=(i)->readAll(); audio_out_streamIn->write(array); } }}//音频输出初始化void Widget::Audio_Out_Init(){ QAudioFormat auido_out_format; //设置录音的格式 auido_out_(44100); //设置采样率以对赫兹采样。 以秒为单位,每秒采集多少声音数据的频率. auido_out_(1); //将通道数设置为通道。 auido_out_(16); /*将样本大小设置为指定的sampleSize(以位为单位)通常为8或16,但是某些系统可能支持更大的样本量。*/ auido_out_("audio/pcm"); //设置编码格式 auido_out_(QAudioFormat::LittleEndian); //样本是小端字节顺序 auido_out_(QAudioFormat::SignedInt); //样本类型 QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); if(audio_out) { delete audio_out; audio_out=nullptr; } audio_out = new QAudioOutput(auido_out_format); audio_out_streamIn=audio_out->start();}// 音频输入初始化void Widget::Audio_in_Init(){ QString text; QAudioFormat auido_input_format; //设置录音的格式 auido_input_(44100); //设置采样率以对赫兹采样。 以秒为单位,每秒采集多少声音数据的频率. auido_input_(1); //将通道数设置为通道。 auido_input_(16); /*将样本大小设置为指定的sampleSize(以位为单位)通常为8或16,但是某些系统可能支持更大的样本量。*/ auido_input_("audio/pcm"); //设置编码格式 auido_input_(QAudioFormat::LittleEndian); //样本是小端字节顺序 auido_input_(QAudioFormat::SignedInt); //样本类型 //选择设备作为输入源 QAudioDeviceInfo info =QAudioDeviceInfo::defaultInputDevice(); ui->plainTextEdit->appendPlainText(tr("当前的录音设备的名字:%1
").arg(())); //判断输入的格式是否支持,如果不支持就使用系统支持的默认格式 if(!(auido_input_format)) { ui->plainTextEdit->appendPlainText("返回与系统支持的提供的设置最接近的QAudioFormat
"); auido_input_format=(auido_input_format); /* * 返回与系统支持的提供的设置最接近的QAudioFormat。 这些设置由所使用的平台/音频插件提供。 它们还取决于所使用的QAudio :: Mode。 */ } //当前设备支持的编码 ui->plainTextEdit->appendPlainText("当前设备支持的编码格式:
"); QStringList list=(); for(int i=0;iplainTextEdit->appendPlainText(text); } ui->plainTextEdit->appendPlainText(tr("当前录音的采样率=%1
").arg(auido_input_())); ui->plainTextEdit->appendPlainText(tr("当前录音的通道数=%1
").arg(auido_input_())); ui->plainTextEdit->appendPlainText(tr("当前录音的样本大小=%1
").arg(auido_input_())); ui->plainTextEdit->appendPlainText(tr("当前录音的编码格式=%1
").arg(auido_input_())); if(audio_in) { delete audio_in; audio_in=nullptr; } audio_in = new QAudioInput(auido_input_format); connect(audio_in,SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleStateChanged_input(QAudio::State)),Qt::QueuedConnection); audio_streamIn=audio_in->start(); //开始音频采集 //关联音频读数据信号 connect(audio_streamIn,SIGNAL(readyRead()),this,SLOT(audio_ReadyRead()),Qt::QueuedConnection);}//有音频信号可以读void Widget::audio_ReadyRead(){ QByteArray byte=audio_streamIn->readAll(); //判断是否处于连接状态 for(int i=0;i<();i++) { //取出地址列表中的一个客户端地址 QTcpSocket *item = (i); //判断该客户端是否已经断开 if(item->socketDescriptor()!=-1) { item->write(byte); } }}//录音状态void Widget::handleStateChanged_input(QAudio::State newState){ switch (newState) { case QAudio::StoppedState: if (audio_in->error() != QAudio::NoError) { // Error handling qDebug()<<"录音出现错误.
"; } else { // Finished recording qDebug()<<"完成录音
"; } break; case QAudio::ActiveState: // Started recording - read from IO device qDebug()<<"开始从IO设备读取PCM声音数据.
"; break; default: // ... other cases as appropriate break; }}void Widget::on_pushButton_clicked(){ Create_Server(); Audio_Out_Init(); Audio_in_Init();}
代码:
#ifndef WIDGET_H#define WIDGET_H#include #include #include #include //获取计算机网络信息#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //这五个是QT处理音频的库#include #include #include #include #include QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget *parent = nullptr); ~Widget(); QTcpServer *LocalTcpServer; QListTcpFarClientList; void Create_Server(); //对讲功能 QThread *audioInputOutput_thread; void Audio_in_Init(); void Audio_Out_Init(); QAudioInput *audio_in; QAudioOutput *audio_out; QIODevice* audio_streamIn; QIODevice* audio_out_streamIn;private slots: void TcpClientDisconnected(); void ReadTcpClientData(); void NewTcpConnection(); void handleStateChanged_input(QAudio::State newState); void audio_ReadyRead(); void on_pushButton_clicked();private: Ui::Widget *ui;};#endif // WIDGET_H
【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】
点击这里:
作者:DS小龙哥 链接:/post/6985337188107943967
关键词: