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文件加载库文件

  1. INCLUDEPATH += C:\work\test\test_audio_record_16k\libspeex1\include
  2. LIBS += -LC:\work\test\test_audio_record_16k\libspeex1 -llibspeex

audio_read.h

  1. #ifndef AUDIO_READ_H
  2. #define AUDIO_READ_H
  3. #include "world.h"
  4. class Audio_Read : public QObject
  5. {
  6. Q_OBJECT
  7. public:
  8. Audio_Read();
  9. signals:
  10. /*********************************************************************
  11. *                           发送网络帧
  12. *参数:frame:发送的报文
  13. **********************************************************************/
  14. void sig_net_tx_frame(QByteArray frame);
  15. public slots:
  16. void readMore();
  17. private:
  18. QAudioInput* audio_in; // class member.
  19. QIODevice *myBuffer_in;
  20. //SPEEX相关全局变量
  21. SpeexBits bits_enc;
  22. void *Enc_State;
  23. short input_frame[SPEEX_FRAME_BYTE / 2];            //speex压缩输入存储区
  24. short input_frame0[SPEEX_FRAME_BYTE / 2];            //speex压缩输入存储区
  25. char cbits[SPEEX_FRAME_BYTE];                       //压缩后数据存储区
  26. char buf[SPEEX_FRAME_BYTE];                         //读取声卡存储区
  27. };
  28. #endif // AUDIO_READ_H

audio_read.cpp 读取声卡,并压缩传输

  1. #include "audio_read.h"
  2. Audio_Read::Audio_Read()
  3. {
  4. //speex编码初始化
  5. speex_bits_init(&bits_enc);
  6. Enc_State = speex_encoder_init(&speex_wb_mode);
  7. //Enc_State = speex_encoder_init(&speex_nb_mode);
  8. //设置压缩质量
  9. int tmp = SPEEX_QUALITY;
  10. speex_encoder_ctl(Enc_State,SPEEX_SET_QUALITY,&tmp);
  11. //声卡采样格式
  12. QAudioFormat format;
  13. // set up the format you want, eg.
  14. format.setSampleRate(16000);
  15. format.setChannelCount(1);
  16. format.setSampleSize(16);
  17. format.setCodec("audio/pcm");
  18. format.setByteOrder(QAudioFormat::LittleEndian);
  19. //format.setByteOrder(QAudioFormat::BigEndian);
  20. format.setSampleType(QAudioFormat::UnSignedInt);
  21. //format.setSampleType(QAudioFormat::SignedInt);
  22. QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
  23. if (!info.isFormatSupported(format)) {
  24. qWarning()<<"default format not supported try to use nearest";
  25. format = info.nearestFormat(format);
  26. }
  27. audio_in = new QAudioInput(format, this);
  28. myBuffer_in = audio_in->start();
  29. connect(myBuffer_in, SIGNAL(readyRead()), SLOT(readMore()));
  30. // Records audio for 3000ms
  31. qDebug() <<"record begin!" << endl;
  32. }
  33. void Audio_Read::readMore()
  34. {
  35. char bytes[800] = {0};
  36. int i = 0;
  37. float input_frame1[320];
  38. QByteArray frame;
  39. int nbytes = 0;
  40. short num = 0;
  41. if (!audio_in)
  42. return;
  43. QByteArray m_buffer(2048,0);
  44. qint64 len = audio_in->bytesReady();
  45. qDebug() << "len1 = " << len;
  46. qint64 l = myBuffer_in->read(m_buffer.data(), len);
  47. qDebug() << "len2 = " << l;
  48. if (len > 640)
  49. {
  50. return;
  51. }
  52. frame.clear();
  53. //将读取的数据转换成speex识别的格式
  54. //大端
  55. for (i = 0;i < 320;i++)
  56. {
  57. num = (uint8_t)m_buffer[2 * i] | ((uint8_t)m_buffer[2 * i + 1] << 8);
  58. input_frame1[i] = num;
  59. }
  60. //    //小端
  61. //    for (i = 0;i < SPEEX_FRAME_BYTE / 2;i++)
  62. //    {
  63. //        input_frame1[i] = m_buffer[2 * i + 1] | ((short)(m_buffer[2 * i]) << 8);
  64. //    }
  65. //    //大端
  66. //    for (i = 0;i < 160;i++)
  67. //    {
  68. //        num = (uint8_t)m_buffer[2 * i] | (((uint8_t)m_buffer[2 * i + 1]) << 8);
  69. //        input_frame1[i] = num;
  70. //        //num = m_buffer[2 * i] | ((short)(m_buffer[2 * i + 1]) << 8);
  71. //        //qDebug() << "float in" << num << input_frame1[i];
  72. //    }
  73. //压缩数据
  74. speex_bits_reset(&bits_enc);
  75. speex_encode(Enc_State,input_frame1,&bits_enc);
  76. nbytes = speex_bits_write(&bits_enc,bytes,800);
  77. qDebug() << "nbytes = " << nbytes;
  78. frame.append(bytes,nbytes);
  79. //    //大端
  80. //    for (i = 0;i < 160;i++)
  81. //    {
  82. //        num = (uint8_t)m_buffer[2 * i + 320] | (((uint8_t)m_buffer[2 * i + 1 + 320]) << 8);
  83. //        input_frame1[i] = num;
  84. //    }
  85. //    //压缩数据
  86. //    speex_bits_reset(&bits_enc);
  87. //    speex_encode(Enc_State,input_frame1,&bits_enc);
  88. //    nbytes = speex_bits_write(&bits_enc,bytes,800);
  89. //    qDebug() << "nbytes = " << nbytes;
  90. //    frame.append(bytes,nbytes);
  91. //发送
  92. //    frame.append(bytes,nbytes);
  93. //    frame.clear();
  94. //    frame.append(m_buffer.data(),len);
  95. if (Server_Ip != QHostAddress("0"))
  96. {
  97. sig_net_tx_frame(frame);
  98. }
  99. }

audio_write.h

  1. #ifndef AUDIO_WRITE_H
  2. #define AUDIO_WRITE_H
  3. #include "world.h"
  4. class Audio_Write : public QObject
  5. {
  6. Q_OBJECT
  7. public:
  8. Audio_Write();
  9. signals:
  10. public slots:
  11. void finishedPlaying(QAudio::State state);
  12. /*********************************************************************
  13. *                           网络接收数据包
  14. *参数:data:接收的数据
  15. **********************************************************************/
  16. void slot_net_rx(QByteArray data);
  17. void update2();
  18. private:
  19. QAudioOutput* audio_out; // class member.
  20. QIODevice *myBuffer_out;
  21. QByteArray Buffer_Play;
  22. //SPEEX相关全局变量
  23. SpeexBits bits_dec;
  24. void *Dec_State;
  25. short output_frame[SPEEX_FRAME_BYTE / 2];           //speex解压输出存储区
  26. };
  27. #endif // AUDIO_WRITE_H

audio_write.cpp 接收语音数据,并解码播放

  1. #include "audio_write.h"
  2. Audio_Write::Audio_Write()
  3. {
  4. //speex初始化
  5. speex_bits_init(&bits_dec);
  6. Dec_State = speex_decoder_init(&speex_wb_mode);
  7. //Dec_State = speex_decoder_init(&speex_nb_mode);
  8. QAudioFormat format;
  9. // set up the format you want, eg.
  10. format.setSampleRate(16000);
  11. format.setChannelCount(1);
  12. format.setSampleSize(16);
  13. format.setCodec("audio/pcm");
  14. format.setByteOrder(QAudioFormat::LittleEndian);
  15. //format.setByteOrder(QAudioFormat::BigEndian);
  16. format.setSampleType(QAudioFormat::UnSignedInt);
  17. //format.setSampleType(QAudioFormat::SignedInt);
  18. QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
  19. if (!info.isFormatSupported(format)) {
  20. qWarning()<<"default format not supported try to use nearest";
  21. format = info.nearestFormat(format);
  22. }
  23. audio_out = new QAudioOutput(format, this);
  24. connect(audio_out,SIGNAL(stateChanged(QAudio::State)),SLOT(finishedPlaying(QAudio::State)));
  25. myBuffer_out = audio_out->start();
  26. qDebug() <<"play begin!" << endl;
  27. QTimer *timer2 = new QTimer(this);
  28. connect(timer2, SIGNAL(timeout()), this, SLOT(update2()));
  29. //timer2->start(10 * INTERVAL);
  30. //timer2->start(5);
  31. }
  32. void Audio_Write::finishedPlaying(QAudio::State state)
  33. {
  34. //   if(state == QAudio::IdleState) {
  35. //     audio_out->stop();
  36. //     inputFile.close();
  37. //     delete audio_out;
  38. //   }
  39. qDebug() << "play end!" << endl;
  40. }
  41. /*********************************************************************
  42. *                               网络接收数据包
  43. *参数:data:接收的数据
  44. **********************************************************************/
  45. void Audio_Write::slot_net_rx(QByteArray data)
  46. {
  47. char bytes[800] = {0};
  48. int i = 0;
  49. float output_frame1[320] = {0};
  50. char buf[800] = {0};
  51. //memcpy(bytes,data.data(),data.length());
  52. qDebug() << "lenght!!!!!!!!!!!!!!" << data.length();
  53. memcpy(bytes,data.data(),data.length());
  54. //解压缩数据106 62
  55. //speex_bits_reset(&bits_dec);
  56. speex_bits_read_from(&bits_dec,bytes,data.length());
  57. int error = speex_decode(Dec_State,&bits_dec,output_frame1);
  58. //qDebug() << "error1 = !!!!!!!!!!!!!!" << error;
  59. //将解压后数据转换为声卡识别格式
  60. //大端
  61. short num = 0;
  62. for (i = 0;i < 320;i++)
  63. {
  64. num = output_frame1[i];
  65. buf[2 * i] = num;
  66. buf[2 * i + 1] = num >> 8;
  67. //qDebug() << "float out" << num << output_frame1[i];
  68. }
  69. //    memcpy(bytes,data.data() + data.length() / 2,data.length() / 2);
  70. //    //解压缩数据
  71. //    //speex_bits_reset(&bits_dec);
  72. //    speex_bits_read_from(&bits_dec,bytes,data.length() / 2);
  73. //    error = speex_decode(Dec_State,&bits_dec,output_frame1);
  74. //    qDebug() << "error2 = !!!!!!!!!!!!!!" << error;
  75. //    //将解压后数据转换为声卡识别格式
  76. //    //大端
  77. //    for (i = 0;i < 160;i++)
  78. //    {
  79. //        num = output_frame1[i];
  80. //        buf[2 * i + 320] = num;
  81. //        buf[2 * i + 1 + 320] = num >> 8;
  82. //    }
  83. //    //小端
  84. //    for (i = 0;i < SPEEX_FRAME_BYTE / 2;i++)
  85. //    {
  86. //        buf[2 * i + 1] = (int)(output_frame1[i]) & 0x00ff;
  87. //        buf[2 * i] = (int)(output_frame1[i]) >> 8;
  88. //    }
  89. //qDebug() << "size!!!" << myBuffer_out->size();
  90. //if (audio_out->state() == QAudio::IdleState)
  91. //{
  92. qDebug() << "播放";
  93. myBuffer_out->write(buf,640);
  94. //Buffer_Play.append(buf,640);
  95. //myBuffer_out->write(data);
  96. //    }
  97. //    else
  98. //    {
  99. //        qDebug() << "忙碌";
  100. //    }
  101. }
  102. void Audio_Write::update2()
  103. {
  104. char bytes[800] = {0};
  105. int i = 0;
  106. QByteArray frame;
  107. //short input_short[L_FRAME] = {0};
  108. int j = 0;
  109. //检查是否有剩余空间
  110. qDebug() << "aaaaaaaaa222222222222222:" << audio_out->bytesFree()
  111. << audio_out->periodSize() << Buffer_Play.length();
  112. if (audio_out && audio_out->state() != QAudio::StoppedState) {
  113. int chunks = audio_out->bytesFree()/audio_out->periodSize();
  114. while (chunks)
  115. {
  116. if (Buffer_Play.length() >= audio_out->periodSize())
  117. {
  118. myBuffer_out->write(Buffer_Play.data(),audio_out->periodSize());
  119. Buffer_Play = Buffer_Play.mid(audio_out->periodSize());
  120. }
  121. else
  122. {
  123. myBuffer_out->write(Buffer_Play);
  124. Buffer_Play.clear();
  125. break;
  126. }
  127. --chunks;
  128. }
  129. }
  130. //    if (Count * L_FRAME_COMPRESSED * INTERVAL > file_all.length())
  131. //    {
  132. //        return;
  133. //    }
  134. //    //发送
  135. //    frame.append(file_all.data() + Count * L_FRAME_COMPRESSED * INTERVAL,L_FRAME_COMPRESSED * INTERVAL);
  136. //    Count++;
  137. //    slot_net_rx(frame);
  138. }

http://blog.csdn.net/jdh99/article/details/39525911

qt中采用宽带speex进行网络语音通话实验程序的更多相关文章

  1. Qt中采用多线程实现Socket编程

    Socket通常也称作"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 本文介绍的是Qt中采用多线程Socket编程,由于工作的需要,开始 ...

  2. 网络语音视频技术浅议 Visual Studio 2010(转)

    我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...

  3. 网络语音视频技术浅议(附多个demo源码下载)

    我们在开发实践中常常会涉及到网络语音视频技术.诸如即时通讯.视频会议.远程医疗.远程教育.网络监控等等,这些网络多媒体应用系统都离不开网络语音视频技术.本人才疏学浅,对于网络语音视频技术也仅仅是略知皮 ...

  4. Qt中sleep()的实现(耳目一新的两种方法)

    在Qt中并没有Sleep函数可以调用,在程序编写时往往需要休眠几秒,这里举出两个方法,不知道是否啥不良隐患没~~ 方法一: class SleeperThread : public QThread{p ...

  5. Qt中的主窗口之菜单栏

    1.Qt中的主窗口 主窗口为建立应用程序用户界面提供了一个框架 Qt开发平台中直接支持主窗口的概念 QMainWindow是Qt中主窗口的基类 QMainWindow继承于QWidget是一种容器类型 ...

  6. Qt中使用的C++知识和技能-你必须要了解的

    如果你不确定在使用Qt编程时自己所掌握的C++知识是否够用,这一节的内容会帮到你.这里给出了Qt自身以及在使用Qt进行编程时涉及到的C++知识,因此,通过阅读本节,你会了解你是否缺少一些C++技能. ...

  7. Qt 框架的图形性能高(OpenGL上的系统效率高),网络性能低,开发效率高,Quick是可以走硬件加速——Qt中分为好几套图形系统,差不多代表了2D描画的发展史。最经典的软描画系统

    -----图形性能部分-----Qt的widgets部分,运行时的图像渲染性能是一般的,因为大部分的界面内容都是Qt自绘,没有走硬件加速,也就是说很多图形内容都是CPU算出来的.但是widgets底层 ...

  8. Qt的action控件中采用默认绑定,没有connect显示绑定!!!

    使用qt创建界面时,可以选用代码设计也可以选用qt design来设计.最近看我同事的代码,以前写action都是使用connect链接槽函数的, 网上大多数人都是这样,然后我就纳闷,怎么没有conn ...

  9. QT中的SOCKET编程(QT-2.3.2)

    转自:http://mylovejsj.blog.163.com/blog/static/38673975200892010842865/ QT中的SOCKET编程 2008-10-07 23:13 ...

随机推荐

  1. 执行hdfs namenode -importCheckpoint时出现No image directories available!

    在https://issues.apache.org/jira/browse/HDFS-4705找到了答案需要在hdfs-site.xml中配置 <!--指定fsimage存储目录--> ...

  2. 人生不过一个字【Life is but a word】

    有人说,人生是一出悲悲喜喜的戏,是一首飘飘忽忽的歌,是一次上去又下来的登山运动,是一场明明灭灭的烟花……是的,有道理,但听起来,太玄虚:悟起来,太深远:做起来,太复杂.              我说 ...

  3. Android之高仿手机QQ聊天

    源代码下载 转载请注明出处,谢谢! 最终版已上传.优化下拉刷新.增加来消息声音提示.主界面改成ViewPager,实现左右滑动.新增群组.最近会话显示条数,开始上班了,不再修改了.谢谢! 国庆这几天, ...

  4. Optimizing concurrent accesses in a directory-based coherency protocol

    In one embodiment, the present invention includes a directory to aid in maintaining control of a cac ...

  5. Store-exclusive instruction conflict resolution

    A data processing system includes a plurality of transaction masters (4, 6, 8, 10) each with an asso ...

  6. XML DTD和XML Schema

    CSDN原文.讲的很清楚.

  7. WebView 联系(要么button)至 Activity 跳跃在几个方面

    第一 ,写一个 JavaScriptinterface 分类.内实现WebView至Activity 页面跳转 public class JavaScriptinterface { Activity ...

  8. Openstack部署总结:“部署过程Error: Local ip for ovs agent must be set when tunneling is enabled”问题

    问题叙述性说明 正在使用RDO当多节点部署测试,因为使用了一些老机器和机器类型的差异(一些HP的PC,有些DELL的PC).以下错误出现: Applying 192.168.40.107_neutro ...

  9. Linux性能测试 sar命令

    sar命令包含在sysstat工具包中,提供系统的众多统计数据.其在不同的系统上命令有些差异 sar 命令行的常用格式: [root@C44 ~]# sar sysstat version (C) S ...

  10. 此C语言功能---A

    功能名称: abort 动力 能够: 异常终止的过程的 使用 法国: void abort(void); 程序示例: #include <stdio.h> #include <std ...