qt中采用窄带speex进行网络语音通话实验程序



qt中采用窄带speex进行网络语音通话实验程序


本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.


环境:

主机:WIN8

开发环境:Qt5 3.1.2

speex版本:1.0.5


说明:

本程序采样频率为8KHz,量化位数为16位,则码率为128kbps。

speex采用窄带压缩,质量10,压缩比率为62/320,则压缩后的码率为24.8kbps。


本测试程序实现网络语音通讯的功能。


源码:

pro文件加载库文件

INCLUDEPATH += C:\work\test\test_audio_record\libspeex1\include LIBS += -LC:\work\test\test_audio_record\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(8000); 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; 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++) // { // input_frame1[i] = m_buffer[2 * i] | ((short)(m_buffer[2 * i + 1]) << 8); // } // //小端 // for (i = 0;i < SPEEX_FRAME_BYTE / 2;i++) // { // input_frame1[i] = m_buffer[2 * i + 1] | ((short)(m_buffer[2 * i]) << 8); // } //大端 short num = 0; 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(8000);
    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() / 2);
    //解压缩数据106 62
    //speex_bits_reset(&bits_dec);
    speex_bits_read_from(&bits_dec,bytes,data.length() / 2);
    int error = speex_decode(Dec_State,&bits_dec,output_frame1);
    //qDebug() << "error1 = !!!!!!!!!!!!!!" << error;

    //将解压后数据转换为声卡识别格式
    //大端
    short num = 0;
    for (i = 0;i < 160;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);
}




你可能感兴趣的:(qt中采用窄带speex进行网络语音通话实验程序)