一年多以前曾经写过一篇用QT  audio语音库实现音频的采集和播放的博文:https://blog.csdn.net/hanzhen7541/article/details/80152381

上面那个是初级版,实现的是从inputdevice音频采集,发送到目的地址端口;目的主机收到音频收到了信号,直接写入音频的设备进行播放。这几天又用到了QT的语音库,所以做了改进,因为网络环境不稳定,所以做了优化:接受端接收到音频流之后,并不直接写在输出的outputdevice进行播放,而是定义了一个缓冲区m_PCMDataBuffer,接受端sicket接收到音频流数据,调用函数addAudioBuffer向缓冲区里面写; 同时,重载了QThread的run函数,调用run()函数,每当缓冲区超过960字节(我社定的8000采样率,16比特采样,960字节对应60ms数据)就从缓冲区读取数据,写入QOutputDevice从而听到声音。

这样当网络不稳定的时候,每一包语音流有不同的延迟,在接受端也能听到较为流畅的声音。

话不多说,现在来看具体代码:

首先是发送线程,这个和之前博文里面的没用太多区别,在主函数中包含头文件之后初始化对象,调用mystart()函数就可以实现发送,调用mystop()函数就可以停止。发送端的头文件:

#ifndef AUDIOSENDTHREAD_H
#define AUDIOSENDTHREAD_H
//这是发送线程#include <QObject>
#include <QThread>
#include <QDebug>#include <QAudio>
#include <QAudioFormat>
#include <QAudioInput>
#include <QAudioOutput>
#include <QIODevice>#include <QtNetwork/QUdpSocket>
#include <QHostAddress>class audiosendthread : public QThread
{Q_OBJECT
public:explicit audiosendthread(QObject *parent = nullptr);~audiosendthread();QUdpSocket *udpSocket;QHostAddress destaddr;QAudioInput *input;QIODevice *inputDevice;QAudioFormat format;struct video{int lens;char data[960];};void setaudioformat(int samplerate, int channelcount, int samplesize);void mystart();void mystop();public slots:void onReadyRead();};#endif // AUDIOSENDTHREAD_H

发送的.cpp

#include "audiosendthread.h"audiosendthread::audiosendthread(QObject *parent): QThread(parent)
{udpSocket = new QUdpSocket(this);udpSocket -> bind(QHostAddress::Any, 10005);destaddr.setAddress("127.0.0.1");//改成你的目的地址就行
}
audiosendthread::~audiosendthread(){delete udpSocket;delete input;delete inputDevice;
}void audiosendthread::setaudioformat(int samplerate, int channelcount, int samplesize){format.setSampleRate(samplerate);format.setChannelCount(channelcount);format.setSampleSize(samplesize);format.setCodec("audio/pcm");format.setSampleType(QAudioFormat::SignedInt);format.setByteOrder(QAudioFormat::LittleEndian);input = new QAudioInput(format, this);}void audiosendthread::mystart(){qDebug()<<"audio begins to send";inputDevice = input->start();connect(inputDevice,SIGNAL(readyRead()),this,SLOT(onReadyRead()));
}void audiosendthread::mystop(){qDebug()<<"audio ends!";input->stop();
}void audiosendthread::onReadyRead(){video vp;memset(&vp.data,0,sizeof(vp));// read audio from input devicevp.lens = inputDevice -> read(vp.data,960);int num = udpSocket -> writeDatagram((const char*)&vp, sizeof(vp),destaddr,10004);qDebug()<<num;
}

以及接受线程的头文件:

#ifndef AUDIO_PLAY_THREAD_H
#define AUDIO_PLAY_THREAD_H
//这是接收线程
#include <QThread>
#include <QObject>
#include <QAudioFormat>
#include <QAudioOutput>
#include <QMutex>
#include <QMutexLocker>
#include <QByteArray>#include <QtNetwork/QUdpSocket>
#include <QHostAddress>
#include <QNetworkInterface>
#include <QDebug>#define MAX_AUDIO_LEN 960000 //如果接收缓冲区大于这个数值就剪掉
#define FRAME_LEN_60ms 960 //每一个语音帧长度是960字节
class AudioPlayThread : public QThread
{Q_OBJECTpublic:AudioPlayThread(QObject *parent = nullptr);~AudioPlayThread();// ----------- 添加数据相关 ----------------------------------------// 设置当前的PCM Buffervoid setCurrentBuffer(QByteArray buffer);// 添加数据void addAudioBuffer(char* pData, int len);// 清空当前的数据void cleanAllAudioBuffer(void);// ------------- End ----------------------------------------------// 设置当前的采样率、采样位数、通道数目void setCurrentSampleInfo(int sampleRate, int sampleSize, int channelCount);virtual void run(void) override;//多线程重载运行函数run// 设置音量void setCurrentVolumn(qreal volumn);void stop();//停止private:QAudioOutput *m_OutPut = nullptr;QIODevice *m_AudioIo = nullptr;QByteArray m_PCMDataBuffer;int m_CurrentPlayIndex = 0;QMutex m_Mutex;// 播放状态volatile bool m_IsPlaying = true;//for AudioQUdpSocket *udpsocket;struct video{int lens;char data[960];};private slots:void readyReadSlot();};#endif

接受线程.cpp

#include "audioplaythread.h"AudioPlayThread::AudioPlayThread(QObject *parent):QThread(parent)
{m_PCMDataBuffer.clear();udpsocket = new QUdpSocket(this);udpsocket->bind(QHostAddress::Any,10004);connect(udpsocket,SIGNAL(readyRead()),this,SLOT(readyReadSlot()));//收到网络数据报就开始往outputDevice写入,进行播放
}AudioPlayThread::~AudioPlayThread()
{delete udpsocket;delete m_OutPut;delete m_AudioIo;}void AudioPlayThread::setCurrentVolumn(qreal volumn){m_OutPut->setVolume(volumn);
}void AudioPlayThread::setCurrentSampleInfo(int sampleRate, int sampleSize, int channelCount)
{QMutexLocker locker(&m_Mutex);// FormatQAudioFormat nFormat;nFormat.setSampleRate(sampleRate);nFormat.setSampleSize(sampleSize);nFormat.setChannelCount(channelCount);nFormat.setCodec("audio/pcm");nFormat.setSampleType(QAudioFormat::SignedInt);nFormat.setByteOrder(QAudioFormat::LittleEndian);if (m_OutPut != nullptr) delete m_OutPut;m_OutPut = new QAudioOutput(nFormat);m_AudioIo = m_OutPut->start();//this->start();
}void AudioPlayThread::run(void)
{while (!this->isInterruptionRequested()){if (!m_IsPlaying){break;}QMutexLocker locker(&m_Mutex);if(m_PCMDataBuffer.size() < m_CurrentPlayIndex + FRAME_LEN_60ms){//缓冲区不够播放60ms音频continue;}else{//拷贝960字节的数据char *writeData = new char[FRAME_LEN_60ms];memcpy(writeData,&m_PCMDataBuffer.data()[m_CurrentPlayIndex], FRAME_LEN_60ms);// 写入音频数据m_AudioIo->write(writeData, FRAME_LEN_60ms);m_CurrentPlayIndex += FRAME_LEN_60ms;qDebug()<<m_CurrentPlayIndex;delete []writeData;//如果长度超过了MAX_AUDIO_LEN就从if(m_CurrentPlayIndex > MAX_AUDIO_LEN){m_PCMDataBuffer = m_PCMDataBuffer.right(m_PCMDataBuffer.size()-MAX_AUDIO_LEN);m_CurrentPlayIndex -= MAX_AUDIO_LEN;}}}m_PCMDataBuffer.clear();qDebug()<<"audio receiver stop!";
}// 添加数据
void AudioPlayThread::addAudioBuffer(char* pData, int len)
{QMutexLocker locker(&m_Mutex);m_PCMDataBuffer.append(pData, len);//m_IsPlaying = true;
}void AudioPlayThread::cleanAllAudioBuffer(void)
{QMutexLocker locker(&m_Mutex);m_CurrentPlayIndex = 0;m_PCMDataBuffer.clear();m_IsPlaying = false;
}void AudioPlayThread::readyReadSlot(){while(udpsocket->hasPendingDatagrams()){QHostAddress senderip;quint16 senderport;qDebug()<<"audio is being received..."<<endl;video vp;memset(&vp,0,sizeof(vp));udpsocket->readDatagram((char*)&vp,sizeof(vp),&senderip,&senderport);//outputDevice->write(vp.data,vp.lens);addAudioBuffer(vp.data, vp.lens);}
}void AudioPlayThread::stop(){udpsocket->close();m_OutPut->stop();cleanAllAudioBuffer();
}

在主函数mainwindow.h中首先定义

    AudioPlayThread aud;
    audiosendthread audsend;

然后在mainwindow.cpp中分别开启两个线程就行了:

    //接受线程启动aud.setCurrentSampleInfo(8000,16,1);aud.setCurrentVolumn(100);aud.start();//发送线程启动audsend.setaudioformat(8000,1,16);audsend.mystart();//... 其他代码//结束两个线程audsend.mystop();aud.stop();

别忘了在.pro文件中首先加入下面两个库,否则会造成编译错误:

  1. QT += network

  2. QT += multimedia

以上就是QT发送接受语音的实现,欢迎指正。

相关代码已经上传至github:   https://github.com/Wzing0421/QTAudio

QT 用QAudio语音库实现音频信号的采集 以及发送到另一台电脑 播放相关推荐

  1. QT 实现采集即时音频信号并发送至另一台电脑播放

    QT有一个音频信号处理的库,非常强大,可以实现音频采集,设定采集的参数等.本文的程序是在一台电脑中实现采集即时音频信号(电脑连接耳机并且说话),将这个音频信号采集后发送至另一台电脑上,在这一台电脑中连 ...

  2. Qt TCP/IP语音

    TCP/IP 语音* 参考文章:[QT 实现采集即时音频信号并发送至另一台电脑播放](https://blog.csdn.net/hanzhen7541/article/details/8015238 ...

  3. ubuntu下,在QT中利用科大讯飞语音库实现语音合成TTS

    首先要去科大讯飞语音库注册,下载linux下的在线合成TTS的SDK,然后在QT下建立一个基于控制台的工程,其实建立关于UI的也可以,问题不大,这里以控制台工程进行说明.将sample中TTS部分的t ...

  4. Qt 配置使用IPP库

    Inter IPP库的简介与配置 1.Inter IPP库简介 IPP"Intel Integrated Performance Primitives" ( Intel IPP ) ...

  5. Qt通讯录(语音输入+发邮件+发短信+头像)

    Qt通讯录(语音输入+发邮件+发短信+头像) 项目背景 功能 运行程序 关键技术 语音识别ASR 发送电子邮件 AddressBook5.0 Gitee地址 项目背景 作为一个Qt小白,迫于大一下学期 ...

  6. QT Creator使用matlab库文件读取.mat文件数据

    QT Creator使用matlab库文件读取.mat文件数据 一.环境配置 二.关于编程介绍 三.关于使用函数的介绍 1:关于假设数据类型介绍 2:关于使用函数介绍 一.环境配置 第一步先点开我的电 ...

  7. qt 的mysql的库

    前段时间,有个莫名其妙的问题困扰了我们好久. 首先是发现,QDir读取文件有问题,并且是有时候可以读,但有时候不可以读的那种.接着是程序中用到的system命令,也是有时候可以执行,但有时执行出错,返 ...

  8. QT调用百度语音REST API实现语音合成

    QT调用百度语音REST API实现语音合成 1.首先点击点击链接http://yuyin.baidu.com/docs/tts 点击access_token,获取access_token,里面有详细 ...

  9. win10语音语言服务器,win10系统:朗读女语音库(发音人)安装方法说明

    win10系统:朗读女语音库(发音人)安装方法说明 朗读女 使用帮助 本文将介绍在win10系统下,朗读女软件如何添加安装:发音人(语音库). 一.安装开启win10系统自带的三个发音人. 1.首先要 ...

最新文章

  1. 网上选课系统java大作业_Java面向对象设计大作业——公选课选课系统
  2. JavaWeb的web.xml标签元素(一)
  3. Linux配置本地yum源(RHEL8)
  4. “富二代”京东健康狂奔,这一次能否赢了阿里?
  5. php7扩展开发教程,Laravel 7 扩展开发教程
  6. mac 删除 Windows 或 EFI Boot 启动盘的方法
  7. Jupyter notebook内使用(添加)虚拟环境
  8. XLSTransformer导出多sheet页
  9. linux基础命令入门到精通
  10. 【洞察】152号令,重量级行业信息技术法规
  11. WMV格式如何转为高清无损MP4视频格式
  12. windows 7 RC(7106.0.090408)下载另附windows7驱动收集整合(5月31日更新)
  13. 天啦噜,游戏音乐制作中有音乐制作人竟然还不够?
  14. 2017北大数学夏令营第一天第二题的解答
  15. 关于使用vue-quill-editor出现p标签的解决方案
  16. 用Python批量把EXCEL表格中的数据提交到网页上
  17. Jhipster生成前端为Vue的项目引入Element-UI
  18. 一年前,月薪两万被人叫老总,如今35岁在美团送外卖
  19. GeoStru.CVSoil.v2014.7.2.47 1CD
  20. vue从服务器获取csv文件,前端 VUE 解析 CSV 文件

热门文章

  1. 为什么都建议学java而不是python-就目前来说,学Java好还是学Python好?
  2. 0基础学python有多难-0基础学Python有多难?
  3. 如何系统的自学python-如何系统地自学 Python?
  4. python练手经典100例-20个Python练手经典案例,能全做对的人确实很少!
  5. 浮云语音转文字识别本地音频文字内容教程
  6. div显示图片_图片按照百分比显示部分,不变形
  7. JavaScript面向对象之Function类型
  8. Node-Promise
  9. 【链表】单链表的排序(归并排序)
  10. 【王道操作系统笔记】进程定义组成组织方式特征