远程语音对讲系统,语音对讲机
1.环境部署QT 版本: 5.12.6 操作系统: Android、Ubuntu、Windows 均已测试。 2、功能介绍实现两个设备之间的语音对讲功能。类似QQ、微信的语音通话效果。使用QAudioInput获取声卡输出,使用QAudioOutpu将数据输出到声卡。语音数据使用TCP 网络双向发送。 (1)对讲APP服务器端:服务器接收客户端发送的数据并播放,同时采集声卡数据并发送给客户端。 (2)对讲APP客户端:接收并播放来自服务器的数据,同时采集声卡数据并发送给服务器。对讲APP服务器端
对讲APP客户端
3. 音频客户端:核心代码
AudioInputOut.h文件代码:#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 '192.168.1.10'#define AUDIO_SERVER_PROT 8888//连接服务器并配置音频接口用于实现com功能类AudioInputOutput : public QObject{ Q_OBJECTpublic: QTcpSocket *LocalTcpClientSocket; AudioInputOutput(QObject*parent=nullptr) :QObject(parent) { LocalTcpClientSocket=nullptr; audio_in=nullptr; audio_out=nullptr; } void TCP_Connect Server( QString Ipaddr), quint16 prot); void Audio_in_Init ( ); void Audio_Out_Init(); QAudioInput *audio_in; QAudioOutput *audio_out; QIODevice* audio_streamIn; QAudio:State newState); void audio_ReadyRead(); void stop_connect();signals: void LogSend(QString text );};# endif //AUDIOINPUTOUT_HAudioInputOut .cpp 文件代码:
#include 'AudioInputOut.h' //创建客户端并连接服务器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('设备连接服务器.'); LogSend('连接服务器.\n');}//客户端模式:断开服务器连接void AudioInputOutput:LocalTcpClientDisconnectedSlot(){ //停止音频input Output audio_in-stop(); audio_out-stop(); LogSend('服务器断开连接。\n');}//客户端模式:读取服务器发送的数据void AudioInputOutput:LocalTcpClientReadDtatSlot (){ QByteArray array=LocalTcpClientSocket-readAll (); } audio_out_streamIn-write(array);} //初始化音频输出void AudioInputOutput:Audio_Out_Init(){ QAudioFormat auido_out_format; //设置录音格式auido_out_format.setSampleRate(44100); //设置采样率以赫兹为单位采样。每秒收集声音数据的频率(以秒为单位) auido_out_format.setChannelCount(1); //设置通道的通道数。 auido_out_format.setSampleSize(16); /*将样本大小设置为指定的样本大小(以位为单位),通常为8 或16,但某些系统可能支持更大的样本大小。 */auido_out_format.setCodec('audio/pcm'); //设置编码格式auido_out_format.setByteOrder(QAudioFormat:LittleEndian); //样本为Little Endian 字节顺序auido_out_format.setSampleType(QAudioFormat:SignedInt); //样本的类型QAudioDeviceInfo information (Q 音频设备信息3 3360: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; QAudio format auido_input_format ; //设置录音的格式auido_input_format.setSampleRate(44100); //设置采样率以赫兹为单位进行采样。每秒收集的声音数据量的频率(以秒为单位) auido_input_format.setChannelCount(1); //将通道号设置为通道。 auido_input_format.setSampleSize(16); /*将样本大小设置为指定的样本大小(以位为单位),通常为8 或16,但某些系统可能支持更大的样本大小。
*/auido_input_format.setcodec('audio/pcm'); //设置编码格式auido_input_format.setbyteorder(qaudioformat:littledian); /sample type //选择设备作为输入源QAudioDeviceInfo info=QAudioDeviceInfo:defaultInputDevice(); Emit LogSend(tr( 'Name of当前录音设备:%1\n').arg(info.deviceName())); //判断是否支持输入格式。如果没有,则使用系统支持的默认格式if(!info.isFormatSupported(auido_input_format)) { Emit LogSend('返回与系统支持的配置最匹配的QAudioFormat\n'); auido_input_format=info.nearestFormat ( auido_input_format);/** 返回最接近系统支持的指定配置的QAudioFormat。这些设置由所使用的平台/音频插件提供。这些还取决于所使用的QAudio : 模式。 */} //当前设备支持的编码退出LogSend('当前设备支持的编码格式:\n'); QStringList list=info.supportedCodecs(); 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:Stat) e newState ){ switch (newState) { case QAudio:StoppedState: if (audio_in-error() !=QAudio:NoError) { //错误处理qDebug()'在录制过程中发生错误。 \n'; } else { //录音完成qDebug( )'完成录音\n'; } Break; case QAudio:ActiveState: //开始录音- 从IO 设备读取qDebug()'IO 开始从设备读取PCM 声音数据。 \n'; Break;default: //.其他可选break; }}//停止连接void AudioInputOutput:stop_connect (){ //判断服务器是否已连接if(LocalTcpClientSocket-socketDescriptor()!=-1) {//断开服务器LocalTcpClientSocket-disconnectFromHost(); //停止音频输入/输出audio_in-stop(); audio_out-stop(); }}RecvServerCMD.h 【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 '127.0.0.1'#define RECV_SERVER_CMD_PROT 6666//连接服务器和s: void LocalTcpClientConnectedSlot(); void LocalTcpClientDisconnectedSlot() ; void LocalTcpClientReadDtatSlot(); void run(); void check_connect();signals: void LogSend (QString text);} ;#endif //RECVSERVERCMD_HRecvServerCMD .cpp
#include 'RecvServerCMD.h' //创建客户端并连接服务器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. 尝试连接服务器Host*/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);}//客户端模式:连接后响应操作。 server void RecvServerCmd:LocalT cpClientConnectedSlot() { LocalTcpClientSocket-write('设备连接服务器。'); LogSend('命令长连接:连接服务器。\n');}//客户端模式:服务器断开void RecvServerCmd:LocalTcpClientDisconnectedSlot () { LogSend('命令长连接:服务器断开。\n');}//客户端模式:读取服务器发送的数据void RecvServerCmd:LocalTcpClientReadDtatSlot(){ QByteArray array=LocalTcpClientSocket-readAll(); qDebug } else { LocalTcpClientSocket-write('device连接ok。'); }} 4.音频服务器端:核心代码
代码widget.cpp 代码:#include 'widget.h'#include 'ui_widget.h'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;QList列表=QNetworkInterface:allAddresses();for(int i=0;icmboBox-addItem(addr.toString());}}}Widget:~Widget(){删除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 ())); TcpFarClientList.append(ServerSocket); //添加目标列表//显示已连接的客户端ui-ClientComboBoxList-clear(); for(int i=0;ipeerAddress().toString() ; info+=':'; info+=QString:number(TcpFarClientList.at( i)-peerPort() ); ui-ClientComboBoxList-addItem(info); }}//服务器模式:响应客户端断开连接void Widget:TcpClientDisconnected() { for(int i=0;isocketDescriptor()==-1) { TcpFarClientList.removeAt(i); } } } //显示已连接的客户端ui-ClientComboBoxList-clear(); for(int i=0;ipeerAddress().toString(); info+=':'; info+=QString:number (TcpFarClientList.at(i)-peerPort( ) ); ui-ClientComboBoxList-addItem(info); }}//服务器模式: 读取数据void Widget:ReadTcpClientData(){ for(i
nt i=0;iatEnd()){ QByteArray array=TcpFarClientList.at(i)->readAll(); audio_out_streamIn->write(array);} }}//音频输出初始化void Widget::Audio_Out_Init(){ QAudioFormat auido_out_format; //设置录音的格式 auido_out_format.setSampleRate(44100); //设置采样率以对赫兹采样。 以秒为单位,每秒采集多少声音数据的频率. auido_out_format.setChannelCount(1); //将通道数设置为通道。 auido_out_format.setSampleSize(16); /*将样本大小设置为指定的sampleSize(以位为单位)通常为8或16,但是某些系统可能支持更大的样本量。*/ auido_out_format.setCodec("audio/pcm"); //设置编码格式 auido_out_format.setByteOrder(QAudioFormat::LittleEndian); //样本是小端字节顺序 auido_out_format.setSampleType(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_format.setSampleRate(44100); //设置采样率以对赫兹采样。 以秒为单位,每秒采集多少声音数据的频率. auido_input_format.setChannelCount(1); //将通道数设置为通道。 auido_input_format.setSampleSize(16); /*将样本大小设置为指定的sampleSize(以位为单位)通常为8或16,但是某些系统可能支持更大的样本量。*/ auido_input_format.setCodec("audio/pcm"); //设置编码格式 auido_input_format.setByteOrder(QAudioFormat::LittleEndian); //样本是小端字节顺序 auido_input_format.setSampleType(QAudioFormat::SignedInt); //样本类型 //选择设备作为输入源 QAudioDeviceInfo info =QAudioDeviceInfo::defaultInputDevice(); ui->plainTextEdit->appendPlainText(tr("当前的录音设备的名字:%1\n").arg(info.deviceName())); //判断输入的格式是否支持,如果不支持就使用系统支持的默认格式 if(!info.isFormatSupported(auido_input_format)) { ui->plainTextEdit->appendPlainText("返回与系统支持的提供的设置最接近的QAudioFormat\n"); auido_input_format=info.nearestFormat(auido_input_format); /** 返回与系统支持的提供的设置最接近的QAudioFormat。 这些设置由所使用的平台/音频插件提供。 它们还取决于所使用的QAudio :: Mode。 */ } //当前设备支持的编码 ui->plainTextEdit->appendPlainText("当前设备支持的编码格式:\n"); QStringList list=info.supportedCodecs(); for(int i=0;iplainTextEdit->appendPlainText(text); } ui->plainTextEdit->appendPlainText(tr("当前录音的采样率=%1\n").arg(auido_input_format.sampleRate())); ui->plainTextEdit->appendPlainText(tr("当前录音的通道数=%1\n").arg(auido_input_format.channelCount())); ui->plainTextEdit->appendPlainText(tr("当前录音的样本大小=%1\n").arg(auido_input_format.sampleSize())); ui->plainTextEdit->appendPlainText(tr("当前录音的编码格式=%1\n").arg(auido_input_format.codec())); 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;isocketDescriptor()!=-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()<<"录音出现错误.\n"; } else { // Finished recording qDebug()<<"完成录音\n"; } break; case QAudio::ActiveState: // Started recording - read from IO device qDebug()<<"开始从IO设备读取PCM声音数据.\n"; break; default: // ... other cases as appropriate break; }}void Widget::on_pushButton_clicked(){ Create_Server(); Audio_Out_Init(); Audio_in_Init();}widget.h代码: #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; QList TcpFarClientList; 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开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】点击这里:Qt资料领取(视频教程+文档+代码+项目实战)作者:DS小龙哥链接:https://juejin.cn/post/6985337188107943967天地劫幽城再临归真4-5攻略:第四章归真4-5八回合图文通关教学[多图],天地劫幽城再临归真4-5怎么样八回合内通
2024-04-19