qt中采用宽带speex进行网络语音通话实验程序
本文博客链接:/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 ""
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.
(16000);
(1);
(16);
("audio/pcm");
(QAudioFormat::LittleEndian);
//(QAudioFormat::BigEndian);
(QAudioFormat::UnSignedInt);
//(QAudioFormat::SignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!(format)) {
qWarning()<<"default format not supported try to use nearest";
format = (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;
}
();
//将读取的数据转换成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;
(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;
// (bytes,nbytes);
//发送
// (bytes,nbytes);
// ();
// (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 ""
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.
(16000);
(1);
(16);
("audio/pcm");
(QAudioFormat::LittleEndian);
//(QAudioFormat::BigEndian);
(QAudioFormat::UnSignedInt);
//(QAudioFormat::SignedInt);
QAudioDeviceInfo info = QAudioDeviceInfo::defaultInputDevice();
if (!(format)) {
qWarning()<<"default format not supported try to use nearest";
format = (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();
// ();
// 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,(),());
qDebug() << "lenght!!!!!!!!!!!!!!" << ();
memcpy(bytes,(),());
//解压缩数据106 62
//speex_bits_reset(&bits_dec);
speex_bits_read_from(&bits_dec,bytes,());
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,() + () / 2,() / 2);
// //解压缩数据
// //speex_bits_reset(&bits_dec);
// speex_bits_read_from(&bits_dec,bytes,() / 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;
// }
// //发送
// (file_all.data() + Count * L_FRAME_COMPRESSED * INTERVAL,L_FRAME_COMPRESSED * INTERVAL);
// Count++;
// slot_net_rx(frame);
}