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 est est_audio_record_16klibspeex1include
- LIBS += -LC:work est est_audio_record_16klibspeex1 -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