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\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 "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); }