打印
[应用相关]

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

[复制链接]
1234|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
八层楼|  楼主 | 2018-10-11 12:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

本文博客链接:http://blog.csdn.net/jdh99,作者:jdh.


环境:

主机:WIN8

开发环境:Qt5 3.1.2

speex版本:1.0.5


说明:

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

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


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


沙发
八层楼|  楼主 | 2018-10-11 12:54 | 只看该作者

源码:

pro文件加载库文件


INCLUDEPATH += C:\work\test\test_audio_record\libspeex1\include
LIBS += -LC:\work\test\test_audio_record\libspeex1 -llibspeex


使用特权

评论回复
板凳
八层楼|  楼主 | 2018-10-11 12:54 | 只看该作者
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


使用特权

评论回复
地板
八层楼|  楼主 | 2018-10-11 12:55 | 只看该作者


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 = m_buffer[2 * i] | ((short)(m_buffer[2 * i + 1]) << 8);
//    }
//    //小端
//    for (i = 0;i < SPEEX_FRAME_BYTE / 2;i++)
//    {
//        input_frame1 = 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 = num;
        //num = m_buffer[2 * i] | ((short)(m_buffer[2 * i + 1]) << 8);
        //qDebug() << "float in" << num << input_frame1;
    }
    //压缩数据
    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 = 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);
    }
}


使用特权

评论回复
5
八层楼|  楼主 | 2018-10-11 12:55 | 只看该作者
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


使用特权

评论回复
6
八层楼|  楼主 | 2018-10-11 12:55 | 只看该作者
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;
        buf[2 * i] = num;
        buf[2 * i + 1] = num >> 8;
        //qDebug() << "float out" << num << output_frame1;
    }

    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;
        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) & 0x00ff;
//        buf[2 * i] = (int)(output_frame1) >> 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);
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

83

主题

3887

帖子

2

粉丝