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. ServletContextListener和ContextLoaderListener的区别

    ServletContext 被 Servlet 程序用来与 Web 容器通信.例如写日志,转发请求.每一个 Web 应用程序含有一个Context,被Web应用内的各个程序共享.因为Context可 ...

  2. android studio 各种问题 应该能帮助到你们

    1. you can import your settings from a previous version of Studio 可以导入您的设置从先前版本的工作室 2. I want to imp ...

  3. CUDA流(Stream)

    CUDA流表示一个GPU操作队列,该队列中的操作将以添加到流中的先后顺序而依次执行.可以将一个流看做是GPU上的一个任务,不同任务可以并行执行.使用CUDA流,首先要选择一个支持设备重叠(Device ...

  4. WPF--3Dmax+blend+WPF综合运用

    引自:http://blog.sina.com.cn/s/blog_95dbdf9e0100we3z.html 本人小菜,WPF刚入门,只是写一下最近的项目心得.欢迎各位前辈们前来拍砖指正,感激不敬! ...

  5. Method and apparatus for establishing IEEE 1588 clock synchronization across a network element comprising first and second cooperating smart interface converters wrapping the network element

    Apparatus for making legacy network elements transparent to IEEE 1588 Precision Time Protocol operat ...

  6. java 压缩以及解压文件,有tar,zip,gz(gizp)和解压

    package com.yabsz.decompCompr; import java.io.File; import java.util.ArrayList; import java.util.Lis ...

  7. 2-5 利用RestTemplateCore简化调用Consul中的服务

    1.必须要安装RestTemplateCore包 2.请求服务,必须要知道 a Consul服务器的地址:b 请求的服务名 ;c 具体请求的api接口 利用RestTemplateCore简化调用Co ...

  8. Tagging Physical Resources in a Cloud Computing Environment

    A cloud system may create physical resource tags to store relationships between cloud computing offe ...

  9. 深入理解最强桌面地图控件GMAP.NET --- 街景地图(StreetView)

    原文:深入理解最强桌面地图控件GMAP.NET --- 街景地图(StreetView) 很久没有更新博客了,今天无事把GMAP.NET的代码又重新翻了翻,看到了街景地图的例子. 街景地图是谷歌最早提 ...

  10. matlab进行离散点的曲线拟合

    原文:matlab进行离散点的曲线拟合 ployfit是matlab中基于最小二乘法的多项式拟合函数.最基础的用法如下: C=polyfit(X,Y,N) 其中: X : 需要拟合的点的横坐标 Y:需 ...