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 ...
随机推荐
- 为什么唱iOS 6.0选择Mantle
近来的mt=8" target="_blank" rel="external">iOS的6.0版本号已经成功上线了. 18人月的投入,2500个 ...
- 写在使用 Linux 工作一年后
start 去年公司空了几台台式机,当时看了下似乎配置比我用的乞丐版 air 略高一些,而且除了 ssd 以外还有一个 1T 的大硬盘,加上后面可能会有一段时间不做 iOS 了,那就不需要 macOS ...
- lua--从白开始(2)
眼下lua最新的版本号,5.2.3. 这个例子是一个简单lua分析器,来源自<Lua游戏开发实践指南>. 测试程序的功能:解决简单lua说明,例如:print("Hello wo ...
- DDD实战6 单元测试
1.在Products解决方案文件夹下面新建一个项目 一个单元测试项目 Product.Tests.
- B 维背包+完全背包 Hdu2159
<span style="color:#3333ff;">/* ---------------------------------------------------- ...
- 简明Python3教程 2.序言
Python也许是为数不多的既简单又强大的编程语言.这有利于新手甚至于专家,更重要的是用它编程所带来的乐趣. 这本书的目的是帮助您了解这种神奇的语言,展示如何快速而轻松地完成事情——事实上”编程问题的 ...
- 使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等
原文:使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等 WPF预设有Aero, Classic, Luna, Royale主题, WPF程序会根据 ...
- 常见信号的模拟仿真(matlab)(spike signal)
1. 一维信号 构造离散时间向量: Fs = 1000; % sampling frequency,采样频率 T = 1/Fs; % sampling period,采样周期 L = 1000; % ...
- poj 2763 Housewife Wind(树链拆分)
id=2763" target="_blank" style="">题目链接:poj 2763 Housewife Wind 题目大意:给定一棵 ...
- Mybatis 一对多 配置文件
当一个Entity中包含的属性有对象和对象集合时,用mybatis映射时要在Entity中添加一个字段来唯一标识当前的Entity对象.否则查询的Entity集合中的对象会被覆盖掉. 如下一个POJO ...