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. 为什么唱iOS 6.0选择Mantle

    近来的mt=8" target="_blank" rel="external">iOS的6.0版本号已经成功上线了. 18人月的投入,2500个 ...

  2. 写在使用 Linux 工作一年后

    start 去年公司空了几台台式机,当时看了下似乎配置比我用的乞丐版 air 略高一些,而且除了 ssd 以外还有一个 1T 的大硬盘,加上后面可能会有一段时间不做 iOS 了,那就不需要 macOS ...

  3. lua--从白开始(2)

    眼下lua最新的版本号,5.2.3. 这个例子是一个简单lua分析器,来源自<Lua游戏开发实践指南>. 测试程序的功能:解决简单lua说明,例如:print("Hello wo ...

  4. DDD实战6 单元测试

    1.在Products解决方案文件夹下面新建一个项目 一个单元测试项目 Product.Tests.

  5. B 维背包+完全背包 Hdu2159

    <span style="color:#3333ff;">/* ---------------------------------------------------- ...

  6. 简明Python3教程 2.序言

    Python也许是为数不多的既简单又强大的编程语言.这有利于新手甚至于专家,更重要的是用它编程所带来的乐趣. 这本书的目的是帮助您了解这种神奇的语言,展示如何快速而轻松地完成事情——事实上”编程问题的 ...

  7. 使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等

    原文:使WPF程序应用预置的控件风格, 如Aero, Luna, Royale, Classic等      WPF预设有Aero, Classic, Luna, Royale主题, WPF程序会根据 ...

  8. 常见信号的模拟仿真(matlab)(spike signal)

    1. 一维信号 构造离散时间向量: Fs = 1000; % sampling frequency,采样频率 T = 1/Fs; % sampling period,采样周期 L = 1000; % ...

  9. poj 2763 Housewife Wind(树链拆分)

    id=2763" target="_blank" style="">题目链接:poj 2763 Housewife Wind 题目大意:给定一棵 ...

  10. Mybatis 一对多 配置文件

    当一个Entity中包含的属性有对象和对象集合时,用mybatis映射时要在Entity中添加一个字段来唯一标识当前的Entity对象.否则查询的Entity集合中的对象会被覆盖掉. 如下一个POJO ...