打印
[应用相关]

qt中采用G.729A进行网络语音通话实验程序

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

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


环境:

主机:WIN8

开发环境:Qt5 3.1.2


说明:

G.729是电话带宽的语音信号编码的标准,G.729A是它的简化版本。

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

G.729A压缩比率为1/16,则压缩后的码率为8kbps。


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


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

源码:

pro文件加载库文件


LIBS += -LC:\mnt\test_audio_record -lva_g729a



使用特权

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

    void update();

private:

    QAudioInput* audio_in; // class member.
    QIODevice *myBuffer_in;

    QByteArray file_all;
    int Count;

    QByteArray buffer_tx;
    int first;

};

#endif // AUDIO_READ_H


使用特权

评论回复
地板
八层楼|  楼主 | 2018-10-11 12:57 | 只看该作者
audio_read.cpp 读取声卡,并压缩传输


#include "audio_read.h"

#define INTERVAL        4

Audio_Read::Audio_Read()
{
    //初始化编码器
    va_g729a_init_encoder();

    //声卡采样格式
    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!" << format.sampleSize();

    QFile file("22.raw");
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "error!!!!!!!!!";
        return;
    }
    file_all = file.readAll();
    Count = 0;
    qDebug() << "hahahahaha" << file_all.length() << (int)file_all[0] <<(int)file_all[1] << (int)file_all[2];

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    //timer->start(10 * INTERVAL);
    //timer->start(5);

    first = 0;
}

void Audio_Read::readMore()
{
    char bytes[800] = {0};
    int i = 0;
    QByteArray frame;

    short input_short[L_FRAME] = {0};
    int j = 0;

    if (!audio_in)
    {
        qDebug() << "error1111111111111111111";
        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 != 0)
    {
        qDebug() << "error2222222222222222222";
        return;
    }

//    if (first < 30)
//    {
//        first++;
//        if (first >= 100)
//        {
//            first = 100;
//        }
//        return;
//    }
//    qDebug() << "ggggggggggggggggg";
    buffer_tx.append(m_buffer.data(),l);

//    for (i = 0;i < 640 / (L_FRAME * 2);i++)
//    {
//        for (j = 0;j < L_FRAME;j++)
//        {
//            input_short[j] = m_buffer[2 * j + i * L_FRAME * 2] |
//                             ((short)(m_buffer[2 * j + 1 + i * L_FRAME * 2]) << 8);
//        }
//        va_g729a_encoder(input_short, (unsigned char *)bytes);
//        frame.append(bytes,L_FRAME_COMPRESSED);
//    }

//    if (Server_Ip == QHostAddress("0"))
//    {
//        return;
//    }


    qDebug() << "length--------------------" << buffer_tx.length();
    short num = 0;
    for (i = 0;i < buffer_tx.length() / (L_FRAME * 2);i++)
    {
        for (j = 0;j < L_FRAME;j++)
        {
            input_short[j] = (uint8_t)buffer_tx[2 * j + i * L_FRAME * 2] |
                             (((uint8_t)buffer_tx[2 * j + 1 + i * L_FRAME * 2]) << 8);
            num = buffer_tx[2 * j + i * L_FRAME * 2] |
                    ((buffer_tx[2 * j + 1 + i * L_FRAME * 2]) << 8);
            qDebug() << "---------!!!!!------------" << num << input_short[j];

        }
        va_g729a_encoder(input_short, (unsigned char *)bytes);
        frame.append(bytes,L_FRAME_COMPRESSED);
    }
    buffer_tx.clear();

    //发送
    if (Server_Ip != QHostAddress("0"))
    {
        //frame.clear();
        //frame.append(m_buffer.data(), len);
        sig_net_tx_frame(frame);
    }
}

void Audio_Read::update()
{
    char bytes[800] = {0};
    int i = 0;
    QByteArray frame;

    short input_short[L_FRAME] = {0};
    int j = 0;

    if (Count * L_FRAME_COMPRESSED * INTERVAL > file_all.length())
    {
        return;
    }

    //发送
    if (Server_Ip != QHostAddress("0"))
    {
        frame.append(file_all.data() + Count * L_FRAME_COMPRESSED * INTERVAL,L_FRAME_COMPRESSED * INTERVAL);
        Count++;
        sig_net_tx_frame(frame);
    }
}


使用特权

评论回复
5
八层楼|  楼主 | 2018-10-11 12:57 | 只看该作者
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 update();
    void update2();

private:

    QAudioOutput* audio_out; // class member.
    QIODevice *myBuffer_out;

    QByteArray Buffer_Play;

    QByteArray file_all;
    int Count;
};

#endif // AUDIO_WRITE_H


使用特权

评论回复
6
八层楼|  楼主 | 2018-10-11 12:58 | 只看该作者
audio_write.cpp 接收语音数据,并解码播放


#include "audio_write.h"

#define INTERVAL        4

Audio_Write::Audio_Write()
{
    //初始化解码器
    va_g729a_init_decoder();

    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::defaultOutputDevice();
    if (!info.isFormatSupported(format)) {
       qWarning()<<"111default 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 *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    //timer->start(10);

    QFile file("22.raw");
    if (!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "error!!!!!!!!!";
        return;
    }
    file_all = file.readAll();
    Count = 0;
    qDebug() << "hahahahaha" << file_all.length() << (int)file_all[0] <<(int)file_all[1] << (int)file_all[2];

    QTimer *timer2 = new QTimer(this);
    connect(timer2, SIGNAL(timeout()), this, SLOT(update2()));
    //timer2->start(10 * INTERVAL);
    timer2->start(5);
}

void Audio_Write::update()
{
    if (Buffer_Play.length() > 0)
    {
        if (Buffer_Play.length() % (L_FRAME * 2) != 0)
        {
            Buffer_Play.clear();
            return;
        }

        myBuffer_out->write(Buffer_Play.data(),L_FRAME * 2);
        Buffer_Play = Buffer_Play.mid(L_FRAME * 2);
        qDebug() << "gogogogo111111111111";
    }
    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);
}

void Audio_Write::finishedPlaying(QAudio::State state)
{
//   if(state == QAudio::IdleState) {
//     audio_out->stop();
//     inputFile.close();
//     delete audio_out;
//   }

   qDebug() << "play end!" << endl;
//   if(state == QAudio::IdleState)
//   {
//       if (Buffer_Play.length() != 0)
//       {
//           myBuffer_out->write(Buffer_Play);
//           Buffer_Play.clear();
//       }
//   }
}

/*********************************************************************
*                               网络接收数据包
*参数:data:接收的数据
**********************************************************************/

void Audio_Write::slot_net_rx(QByteArray data)
{
    char bytes[800] = {0};
    int i = 0;

    short output_short[L_FRAME] = {0};
    int j = 0;
    QByteArray frame;

    //memcpy(bytes,data.data(),data.length());

    qDebug() << "lenght!!!!!!!!!!!!!!" << data.length();

    for (i = 0;i < data.length() / L_FRAME_COMPRESSED;i++)
    {
        va_g729a_decoder((unsigned char*)data.data() + i * L_FRAME_COMPRESSED, output_short, 0);

        for (j = 0;j < L_FRAME;j++)
        {
            bytes[j * 2] = output_short[j];
            bytes[j * 2 + 1] = output_short[j] >> 8;
        }
        frame.append(bytes,L_FRAME * 2);
    }
//    int k = 0;
//    for (i = 0;i < data.length() / L_FRAME_COMPRESSED;i++)
//    {
//        va_g729a_decoder((unsigned char*)data.data() + i * L_FRAME_COMPRESSED, output_short, 0);

//        for (j = 0;j < L_FRAME;j++)
//        {
//            bytes[k++] = output_short[j];
//            bytes[k++] = output_short[j] >> 8;
//        }
//    }

    //qDebug() << "size!!!" << myBuffer_out->size();
    //if (audio_out->state() == QAudio::IdleState)
    //{
        qDebug() << "播放";
        //myBuffer_out->write(frame);
//        if (audio_out->state() == QAudio::IdleState)
//        {
//            myBuffer_out->write(frame);
//            Buffer_Play.clear();
//        }
//        else
//        {
            Buffer_Play.append(frame);
        //}
        qDebug() << "gogogogo2222222";
        //myBuffer_out->write(data);
        //myBuffer_out->write(bytes,k);
//    }
//    else
//    {
//        qDebug() << "忙碌";
//    }
}


使用特权

评论回复
7
八层楼|  楼主 | 2018-10-11 12:58 | 只看该作者
va_g729a.h 注意函数前加extern "C"


/*--------------------------------------------------------------------------------*
*                                                                                *
* This material is trade secret owned by VoiceAge Corporation                    *
* and is strictly confidential and shall remain as such.                         *
*                                                                                *
* Copyright ?1995-2001 VoiceAge Corporation. All Rights Reserved. No part of    *
* this material may be reproduced, stored in a retrieval system, or transmitted, *
* in any form or by any means, including, but not limited to, photocopying,      *
*  electronic, mechanical, recording, or otherwise, without the prior written    *
* permission of VoiceAge Corporation.                                            *
*                                                                                *
* This material is subject to continuous developments and improvements. All      *
* warranties implied or expressed, including but not limited to implied          *
* warranties of merchantability, or fitness for purpose, are excluded.           *
*                                                                                *
* ACELP and VoiceAge are registered trademark and trademark of VoiceAge          *
* Corporation in Canada and / or other countries. Any unauthorized use is        *
* strictly prohibited.                                                           *
*                                                                                *
*--------------------------------------------------------------------------------*
*                                                                                *
* VoiceAge Corporation                                                           *
* 750, Chemin Lucerne                                                            *
* Suite 250                                                                      *
* Ville Mont-Royal (Quebec)                                                      *
* Canada, H3R 2H6                                                                *
*                                                                                *
* Tel. (514) 737-4940, fax. (514) 908-2037                                       *
*                                                                                *
*--------------------------------------------------------------------------------*
*
*--------------------------------------------------------------------------------*
*                            va_g729a.h                                          *
*                         ~~~~~~~~~~~~~~~~~~                                     *
*--------------------------------------------------------------------------------*
va_g729a API functions prototypes and constants */

#define  L_FRAME_COMPRESSED 10
#define  L_FRAME            80

extern "C" void va_g729a_init_encoder();
extern "C" void va_g729a_encoder(short *speech, unsigned char *bitstream);
extern "C" void va_g729a_init_decoder();
extern "C" void va_g729a_decoder(unsigned char *bitstream, short *synth_short, int bfi);


使用特权

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

本版积分规则

91

主题

4146

帖子

2

粉丝