qt中采用G.729A进行网络语音通话实验程序
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.
环境:
主机:WIN8
开发环境:Qt5 3.1.2
说明:
G.729是电话带宽的语音信号编码的标准,G.729A是它的简化版本。
本程序采样频率为8KHz,量化位数为16位,则码率为128kbps。
G.729A压缩比率为1/16,则压缩后的码率为8kbps。
本测试程序实现网络语音通讯的功能。
源码:
pro文件加载库文件
LIBS += -LC:\mnt\test_audio_record -lva_g729a
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
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);
}
}
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
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() << "忙碌";
// }
}
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);