qt中采用宽带speex进行网络语音通话实验程序
qt中采用宽带speex进行网络语音通话实验程序
本文博客链接:http://blog.csdn.NET/jdh99,作者:jdh,转载请注明.
环境:
主机:WIN8
开发环境:Qt5 3.1.2
speex版本:1.0.5
说明:
本程序采样频率为16KHz,量化位数为16位,则码率为256kbps。
speex采用窄带压缩,质量10,压缩比率为106/640,则压缩后的码率为42.4kbps。
本测试程序实现网络语音通讯的功能。
源码:
pro文件加载库文件
- INCLUDEPATH += C:\work\test\test_audio_record_16k\libspeex1\include
- LIBS += -LC:\work\test\test_audio_record_16k\libspeex1 -llibspeex
audio_read.h
- #ifndef AUDIO_READ_H
- #define AUDIO_READ_H
- #include "world.h"
- class Audio_Read : public QObject
- {
- Q_OBJECT
- public:
- Audio_Read();
- signals:
- /*********************************************************************
- * 发送网络帧
- *参数:frame:发送的报文
- **********************************************************************/
- void sig_net_tx_frame(QByteArray frame);
- public slots:
- void readMore();
- private:
- QAudioInput* audio_in; // class member.
- QIODevice *myBuffer_in;
- //SPEEX相关全局变量
- SpeexBits bits_enc;
- void *Enc_State;
- short input_frame[SPEEX_FRAME_BYTE / 2]; //speex压缩输入存储区
- short input_frame0[SPEEX_FRAME_BYTE / 2]; //speex压缩输入存储区
- char cbits[SPEEX_FRAME_BYTE]; //压缩后数据存储区
- char buf[SPEEX_FRAME_BYTE]; //读取声卡存储区
- };
- #endif // AUDIO_READ_H
audio_read.cpp 读取声卡,并压缩传输
- #include "audio_read.h"
- Audio_Read::Audio_Read()
- {
- //speex编码初始化
- speex_bits_init(&bits_enc);
- Enc_State = speex_encoder_init(&speex_wb_mode);
- //Enc_State = speex_encoder_init(&speex_nb_mode);
- //设置压缩质量
- int tmp = SPEEX_QUALITY;
- speex_encoder_ctl(Enc_State,SPEEX_SET_QUALITY,&tmp);
- //声卡采样格式
- QAudioFormat format;
- // set up the format you want, eg.
- format.setSampleRate(16000);
- format.setChannelCount(1);
- format.setSampleSize(16);
- format.setCodec("audio/pcm");
- format.setByteOrder(QAudioFormat::LittleEndian);
- //format.setByteOrder(QAudioFormat::BigEndian);
- format.setSampleType(QAudioFormat::UnSignedInt);
- //format.setSampleType(QAudioFormat::SignedInt);
- QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
- if (!info.isFormatSupported(format)) {
- qWarning()<<"default format not supported try to use nearest";
- format = info.nearestFormat(format);
- }
- audio_in = new QAudioInput(format, this);
- myBuffer_in = audio_in->start();
- connect(myBuffer_in, SIGNAL(readyRead()), SLOT(readMore()));
- // Records audio for 3000ms
- qDebug() <<"record begin!" << endl;
- }
- void Audio_Read::readMore()
- {
- char bytes[800] = {0};
- int i = 0;
- float input_frame1[320];
- QByteArray frame;
- int nbytes = 0;
- short num = 0;
- if (!audio_in)
- return;
- QByteArray m_buffer(2048,0);
- qint64 len = audio_in->bytesReady();
- qDebug() << "len1 = " << len;
- qint64 l = myBuffer_in->read(m_buffer.data(), len);
- qDebug() << "len2 = " << l;
- if (len > 640)
- {
- return;
- }
- frame.clear();
- //将读取的数据转换成speex识别的格式
- //大端
- for (i = 0;i < 320;i++)
- {
- num = (uint8_t)m_buffer[2 * i] | ((uint8_t)m_buffer[2 * i + 1] << 8);
- input_frame1[i] = num;
- }
- // //小端
- // for (i = 0;i < SPEEX_FRAME_BYTE / 2;i++)
- // {
- // input_frame1[i] = m_buffer[2 * i + 1] | ((short)(m_buffer[2 * i]) << 8);
- // }
- // //大端
- // for (i = 0;i < 160;i++)
- // {
- // num = (uint8_t)m_buffer[2 * i] | (((uint8_t)m_buffer[2 * i + 1]) << 8);
- // input_frame1[i] = num;
- // //num = m_buffer[2 * i] | ((short)(m_buffer[2 * i + 1]) << 8);
- // //qDebug() << "float in" << num << input_frame1[i];
- // }
- //压缩数据
- speex_bits_reset(&bits_enc);
- speex_encode(Enc_State,input_frame1,&bits_enc);
- nbytes = speex_bits_write(&bits_enc,bytes,800);
- qDebug() << "nbytes = " << nbytes;
- frame.append(bytes,nbytes);
- // //大端
- // for (i = 0;i < 160;i++)
- // {
- // num = (uint8_t)m_buffer[2 * i + 320] | (((uint8_t)m_buffer[2 * i + 1 + 320]) << 8);
- // input_frame1[i] = num;
- // }
- // //压缩数据
- // speex_bits_reset(&bits_enc);
- // speex_encode(Enc_State,input_frame1,&bits_enc);
- // nbytes = speex_bits_write(&bits_enc,bytes,800);
- // qDebug() << "nbytes = " << nbytes;
- // frame.append(bytes,nbytes);
- //发送
- // frame.append(bytes,nbytes);
- // frame.clear();
- // frame.append(m_buffer.data(),len);
- if (Server_Ip != QHostAddress("0"))
- {
- sig_net_tx_frame(frame);
- }
- }
audio_write.h
- #ifndef AUDIO_WRITE_H
- #define AUDIO_WRITE_H
- #include "world.h"
- class Audio_Write : public QObject
- {
- Q_OBJECT
- public:
- Audio_Write();
- signals:
- public slots:
- void finishedPlaying(QAudio::State state);
- /*********************************************************************
- * 网络接收数据包
- *参数:data:接收的数据
- **********************************************************************/
- void slot_net_rx(QByteArray data);
- void update2();
- private:
- QAudioOutput* audio_out; // class member.
- QIODevice *myBuffer_out;
- QByteArray Buffer_Play;
- //SPEEX相关全局变量
- SpeexBits bits_dec;
- void *Dec_State;
- short output_frame[SPEEX_FRAME_BYTE / 2]; //speex解压输出存储区
- };
- #endif // AUDIO_WRITE_H
audio_write.cpp 接收语音数据,并解码播放
- #include "audio_write.h"
- Audio_Write::Audio_Write()
- {
- //speex初始化
- speex_bits_init(&bits_dec);
- Dec_State = speex_decoder_init(&speex_wb_mode);
- //Dec_State = speex_decoder_init(&speex_nb_mode);
- QAudioFormat format;
- // set up the format you want, eg.
- format.setSampleRate(16000);
- format.setChannelCount(1);
- format.setSampleSize(16);
- format.setCodec("audio/pcm");
- format.setByteOrder(QAudioFormat::LittleEndian);
- //format.setByteOrder(QAudioFormat::BigEndian);
- format.setSampleType(QAudioFormat::UnSignedInt);
- //format.setSampleType(QAudioFormat::SignedInt);
- QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
- if (!info.isFormatSupported(format)) {
- qWarning()<<"default format not supported try to use nearest";
- format = info.nearestFormat(format);
- }
- audio_out = new QAudioOutput(format, this);
- connect(audio_out,SIGNAL(stateChanged(QAudio::State)),SLOT(finishedPlaying(QAudio::State)));
- myBuffer_out = audio_out->start();
- qDebug() <<"play begin!" << endl;
- QTimer *timer2 = new QTimer(this);
- connect(timer2, SIGNAL(timeout()), this, SLOT(update2()));
- //timer2->start(10 * INTERVAL);
- //timer2->start(5);
- }
- void Audio_Write::finishedPlaying(QAudio::State state)
- {
- // if(state == QAudio::IdleState) {
- // audio_out->stop();
- // inputFile.close();
- // delete audio_out;
- // }
- qDebug() << "play end!" << endl;
- }
- /*********************************************************************
- * 网络接收数据包
- *参数:data:接收的数据
- **********************************************************************/
- void Audio_Write::slot_net_rx(QByteArray data)
- {
- char bytes[800] = {0};
- int i = 0;
- float output_frame1[320] = {0};
- char buf[800] = {0};
- //memcpy(bytes,data.data(),data.length());
- qDebug() << "lenght!!!!!!!!!!!!!!" << data.length();
- memcpy(bytes,data.data(),data.length());
- //解压缩数据106 62
- //speex_bits_reset(&bits_dec);
- speex_bits_read_from(&bits_dec,bytes,data.length());
- int error = speex_decode(Dec_State,&bits_dec,output_frame1);
- //qDebug() << "error1 = !!!!!!!!!!!!!!" << error;
- //将解压后数据转换为声卡识别格式
- //大端
- short num = 0;
- for (i = 0;i < 320;i++)
- {
- num = output_frame1[i];
- buf[2 * i] = num;
- buf[2 * i + 1] = num >> 8;
- //qDebug() << "float out" << num << output_frame1[i];
- }
- // memcpy(bytes,data.data() + data.length() / 2,data.length() / 2);
- // //解压缩数据
- // //speex_bits_reset(&bits_dec);
- // speex_bits_read_from(&bits_dec,bytes,data.length() / 2);
- // error = speex_decode(Dec_State,&bits_dec,output_frame1);
- // qDebug() << "error2 = !!!!!!!!!!!!!!" << error;
- // //将解压后数据转换为声卡识别格式
- // //大端
- // for (i = 0;i < 160;i++)
- // {
- // num = output_frame1[i];
- // buf[2 * i + 320] = num;
- // buf[2 * i + 1 + 320] = num >> 8;
- // }
- // //小端
- // for (i = 0;i < SPEEX_FRAME_BYTE / 2;i++)
- // {
- // buf[2 * i + 1] = (int)(output_frame1[i]) & 0x00ff;
- // buf[2 * i] = (int)(output_frame1[i]) >> 8;
- // }
- //qDebug() << "size!!!" << myBuffer_out->size();
- //if (audio_out->state() == QAudio::IdleState)
- //{
- qDebug() << "播放";
- myBuffer_out->write(buf,640);
- //Buffer_Play.append(buf,640);
- //myBuffer_out->write(data);
- // }
- // else
- // {
- // qDebug() << "忙碌";
- // }
- }
- void Audio_Write::update2()
- {
- char bytes[800] = {0};
- int i = 0;
- QByteArray frame;
- //short input_short[L_FRAME] = {0};
- int j = 0;
- //检查是否有剩余空间
- qDebug() << "aaaaaaaaa222222222222222:" << audio_out->bytesFree()
- << audio_out->periodSize() << Buffer_Play.length();
- if (audio_out && audio_out->state() != QAudio::StoppedState) {
- int chunks = audio_out->bytesFree()/audio_out->periodSize();
- while (chunks)
- {
- if (Buffer_Play.length() >= audio_out->periodSize())
- {
- myBuffer_out->write(Buffer_Play.data(),audio_out->periodSize());
- Buffer_Play = Buffer_Play.mid(audio_out->periodSize());
- }
- else
- {
- myBuffer_out->write(Buffer_Play);
- Buffer_Play.clear();
- break;
- }
- --chunks;
- }
- }
- // if (Count * L_FRAME_COMPRESSED * INTERVAL > file_all.length())
- // {
- // return;
- // }
- // //发送
- // frame.append(file_all.data() + Count * L_FRAME_COMPRESSED * INTERVAL,L_FRAME_COMPRESSED * INTERVAL);
- // Count++;
- // slot_net_rx(frame);
- }
http://blog.csdn.net/jdh99/article/details/39525911
qt中采用宽带speex进行网络语音通话实验程序的更多相关文章
- Qt中采用多线程实现Socket编程
Socket通常也称作"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 本文介绍的是Qt中采用多线程Socket编程,由于工作的需要,开始 ...
- 网络语音视频技术浅议 Visual Studio 2010(转)
我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...
- 网络语音视频技术浅议(附多个demo源码下载)
我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...
- Qt中sleep()的实现(耳目一新的两种方法)
在Qt中并没有Sleep函数可以调用,在程序编写时往往需要休眠几秒,这里举出两个方法,不知道是否啥不良隐患没~~ 方法一: class SleeperThread : public QThread{p ...
- Qt中的主窗口之菜单栏
1.Qt中的主窗口 主窗口为建立应用程序用户界面提供了一个框架 Qt开发平台中直接支持主窗口的概念 QMainWindow是Qt中主窗口的基类 QMainWindow继承于QWidget是一种容器类型 ...
- Qt中使用的C++知识和技能-你必须要了解的
如果你不确定在使用Qt编程时自己所掌握的C++知识是否够用,这一节的内容会帮到你.这里给出了Qt自身以及在使用Qt进行编程时涉及到的C++知识,因此,通过阅读本节,你会了解你是否缺少一些C++技能. ...
- Qt 框架的图形性能高(OpenGL上的系统效率高),网络性能低,开发效率高,Quick是可以走硬件加速——Qt中分为好几套图形系统,差不多代表了2D描画的发展史。最经典的软描画系统
-----图形性能部分-----Qt的widgets部分,运行时的图像渲染性能是一般的,因为大部分的界面内容都是Qt自绘,没有走硬件加速,也就是说很多图形内容都是CPU算出来的.但是widgets底层 ...
- Qt的action控件中采用默认绑定,没有connect显示绑定!!!
使用qt创建界面时,可以选用代码设计也可以选用qt design来设计.最近看我同事的代码,以前写action都是使用connect链接槽函数的, 网上大多数人都是这样,然后我就纳闷,怎么没有conn ...
- QT中的SOCKET编程(QT-2.3.2)
转自:http://mylovejsj.blog.163.com/blog/static/38673975200892010842865/ QT中的SOCKET编程 2008-10-07 23:13 ...
随机推荐
- sparksql hive作为数据源
根据官方文档的说法,要把hive-site.xml,core-site.xml,hdfs-site.xml拷贝到spark的conf目录下,保证mysql已经启动 java public class ...
- Servlet接口的实现类,路径配置映射,ServletConfig对象,ServletContext对象及web工程中文件的读取
一,Servlet接口实现类:sun公司为Servlet接口定义了两个默认的实现类,分别为:GenericServlet和HttpServlet. HttpServlet:指能够处理HTTP请求的se ...
- IOC介绍及其简单实现
预备知识: Java反射原理,XML及其解析 IOC:Inversion of Control,控制反转,它最主要反映的是与传统面向对象(OO)编程的不同.通常我们编程实现某种功能都需要几个对象相 ...
- 各种工具的使用 tricks
1. 搜狗搜索引擎 因为搜狗与腾讯的合作关系,搜狗搜索引擎提供了"微信"的搜索选项,可直接定位到相关文章,或者公众号. weixin.sougou.com 2. PyCharm P ...
- 移动端--web开展
近期看到群里对关于 移动端 web开发非常是感兴趣.决定写一个关于 移动端的web开发 概念或框架(宝庆对此非常是纠结).也是由于自己一直从事pc 浏览器 web一直对 移动端的不是非常重视,所以趁此 ...
- intel edison with grove lcd
由intel xdk,例如,下面的过程能够打印Hello world至grove lcd上 var mraa = require ('mraa'); var LCD = require ('jsupm ...
- Expression Design与Blend制作滚动的小球动画教程
原文:Expression Design与Blend制作滚动的小球动画教程 一,开发工具 Microsoft Expression Design & Blend 4.0 (3.0亦可). 这两 ...
- 如何使用GDI绘制半透明矩形
/*使用GDI绘制半透明矩形*/ void CDirectXDraw::DrawHalfOpacityRect(HDC hdc,CRect rect) { CDC dc; dc.Attach(hdc) ...
- git clone命令简介
git clone: 正如上图,当我们打开终端的情况下,默认我们所在的目录是在/home/shiyanlou的,大家可以在终端输入以下命令把目录切换到桌面cd /home/Desktop这个时候输入 ...
- 使用Qt installer framework制作安装包(不知道是否适合Mac和Linux?)
一.介绍 使用Qt库开发的应用程序,一般有两种发布方式:(1)静态编译发布.这种方式使得程序在编译的时候会将Qt核心库全部编译到一个可执行文件中.其优势是简单单一,所有的依赖库都集中在一起,其缺点也很 ...