前言:
眼前小伙伴们对“ubuntu录音”大体比较注重,姐妹们都需要剖析一些“ubuntu录音”的相关知识。那么小编也在网上网罗了一些关于“ubuntu录音””的相关知识,希望兄弟们能喜欢,同学们快快来学习一下吧!一、环境介绍
QT版本: 5.12.6
操作系统: Android、ubuntu、windows 都测试OK。
二、功能介绍
两台设备之间实现语音对讲功能。类似于QQ、微信语音电话效果。
采用QAudioInput获取声卡输出,QAudioOutpu用于输出数据到声卡。
音频数据采用TCP网络方式双向传输。
(1)对讲APP服务器端: 服务器收到客户端的数据就播放,同时采集声卡数据发送给客户端。
(2) 对讲APP客户端:客户端收到服务器的数据就播放,同时采集声卡数据发送给服务器。
对讲APP服务器端
对讲APP客户端
三、音频客户端: 核心代码
AudioInputOut.h文件代码:
#ifndef AUDIOINPUTOUT_H#define AUDIOINPUTOUT_H#include <QObject>#include <QWidget>#include <QTcpServer>#include <QHostInfo> //获取计算机网络信息#include <QUdpSocket>#include <QtNetwork>#include <QHostInfo>#include <QDebug>#include <QTcpSocket>#include <QHostAddress>#include <QDebug>#include <QMessageBox>#include <QLineEdit>#include <QHBoxLayout>#include <QComboBox>#include <QFile>#include <QTimer>#include <QScrollBar>#include <QScrollBar>#include <QAudio> //这五个是QT处理音频的库#include <QAudioFormat>#include <QAudioInput>#include <QAudioOutput>#include <QIODevice>#define AUDIO_SERVER_IP "192.168.1.10"#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
AudioInputOut.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("device connect server."); LogSend("连接上服务器.\n");}//客户端模式:断开服务器void AudioInputOutput::LocalTcpClientDisconnectedSlot(){ //停止音频输入输出 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); /*将样本大小设置为指定的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 AudioInputOutput::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(); emit LogSend(tr("当前的录音设备的名字:%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 :: Mode。 */ } //当前设备支持的编码 emit LogSend("当前设备支持的编码格式:\n"); QStringList list=info.supportedCodecs(); for(int i=0;i<list.size();i++) { text=list.at(i)+"\n"; emit LogSend(text); } emit LogSend(tr("当前录音的采样率=%1\n").arg(auido_input_format.sampleRate())); emit LogSend(tr("当前录音的通道数=%1\n").arg(auido_input_format.channelCount())); emit LogSend(tr("当前录音的样本大小=%1\n").arg(auido_input_format.sampleSize())); emit LogSend(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 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()<<"录音出现错误.\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 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 <QObject>#include <QWidget>#include <QTcpServer>#include <QHostInfo> //获取计算机网络信息#include <QUdpSocket>#include <QtNetwork>#include <QHostInfo>#include <QDebug>#include <QTcpSocket>#include <QHostAddress>#include <QDebug>#include <QMessageBox>#include <QLineEdit>#include <QHBoxLayout>#include <QComboBox>#include <QFile>#include <QTimer>#include <QScrollBar>#include <QScrollBar>#include <QAudio> //这五个是QT处理音频的库#include <QAudioFormat>#include <QAudioInput>#include <QAudioOutput>#include <QIODevice>#include <QTimer>#define RECV_SERVER_CMD_IP "127.0.0.1"#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
RecvServerCMD.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. 尝试连接服务器主机*/ 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("命令长连接:连接上服务器.\n");}//客户端模式:断开服务器void RecvServerCmd::LocalTcpClientDisconnectedSlot(){ LogSend("命令长连接:服务器断开.\n");}//客户端模式:读取服务器发过来的数据void RecvServerCmd::LocalTcpClientReadDtatSlot(){ QByteArray array=LocalTcpClientSocket->readAll(); qDebug()<<"服务器下发的命令:"<<array; LocalTcpClientSocket->write(array);}//心跳包void RecvServerCmd::check_connect(){ //判断该客户端是否已经断开 if(LocalTcpClientSocket->socketDescriptor()==-1) { /*4. 尝试连接服务器主机*/ LocalTcpClientSocket->connectToHost(QHostAddress(RECV_SERVER_CMD_IP),RECV_SERVER_CMD_PROT); } else { LocalTcpClientSocket->write("device connect ok."); }}
四、音频服务器端: 核心代码
码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<QHostAddress> list = QNetworkInterface::allAddresses(); for(int i=0;i<list.count();i++) { QHostAddress addr=list.at(i); if(addr.protocol() == QAbstractSocket::IPv4Protocol) { ui->comboBox->addItem(addr.toString()); } }}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())); TcpFarClientList.append(ServerSocket);//添加到列表 //显示已经连接的客户端 ui->ClientComboBoxList->clear(); for(int i=0;i<TcpFarClientList.count();i++) { QString info=TcpFarClientList.at(i)->peerAddress().toString(); info+=":"; info+=QString::number(TcpFarClientList.at(i)->peerPort()); ui->ClientComboBoxList->addItem(info); }}//服务器模式:响应断开的客户端void Widget::TcpClientDisconnected(){ for(int i=0;i<TcpFarClientList.count();i++) { //取出地址列表中的一个客户端地址 QTcpSocket *item = TcpFarClientList.at(i); //判断该客户端是否已经断开 if(item->socketDescriptor()==-1) { TcpFarClientList.removeAt(i); } } //显示已经连接的客户端 ui->ClientComboBoxList->clear(); for(int i=0;i<TcpFarClientList.count();i++) { QString info=TcpFarClientList.at(i)->peerAddress().toString(); info+=":"; info+=QString::number(TcpFarClientList.at(i)->peerPort()); ui->ClientComboBoxList->addItem(info); }}//服务器模式:读数据void Widget::ReadTcpClientData(){ for(int i=0;i<TcpFarClientList.count();i++) { if(!TcpFarClientList.at(i)->atEnd()) { 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;i<list.size();i++) { text=list.at(i)+"\n"; ui->plainTextEdit->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;i<TcpFarClientList.count();i++) { //取出地址列表中的一个客户端地址 QTcpSocket *item = TcpFarClientList.at(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()<<"录音出现错误.\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 <QWidget>#include <QWidget>#include <QTcpServer>#include <QHostInfo> //获取计算机网络信息#include <QUdpSocket>#include <QtNetwork>#include <QHostInfo>#include <QDebug>#include <QTcpSocket>#include <QHostAddress>#include <QDebug>#include <QMessageBox>#include <QLineEdit>#include <QHBoxLayout>#include <QComboBox>#include <QFile>#include <QTimer>#include <QScrollBar>#include <QScrollBar>#include <QAudio> //这五个是QT处理音频的库#include <QAudioFormat>#include <QAudioInput>#include <QAudioOutput>#include <QIODevice>#include <QDebug>QT_BEGIN_NAMESPACEnamespace Ui { class Widget; }QT_END_NAMESPACEclass Widget : public QWidget{ Q_OBJECTpublic: Widget(QWidget *parent = nullptr); ~Widget(); QTcpServer *LocalTcpServer; QList<QTcpSocket*> 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小龙哥
链接:
版权声明:
本站文章均来自互联网搜集,如有侵犯您的权益,请联系我们删除,谢谢。
标签: #ubuntu录音