There are five header files in Voiceengine that are related to the simplest voice chat, as shown in the following table:
Header file |
Included classes
|
Description |
Voe_base.h |
Voiceengineobserver Voiceengine Voebase
|
1. Default use of g.711 for full-duplex VoIP sessions via RTP 2. Initialization and termination 3. Tracking information through files and callback functions 4. Multi-channel support (e.g. mixing, sending to multiple destinations) 5. If you want to support g.711 outside of the code, you need to Voecodec |
Voe_errors.h |
No
|
Definitions of some Voiceengine related errors
|
Voe_network.h |
Voenetwork
|
1. Extended protocol Support
2. Packet Timeout prompt
3. Monitor if the connection is disconnected
|
Voe_hardware.h |
Voehardware |
1. Managing Audio Devices
2. Get device information 3. Sample rate setting
|
Voe_volume_control.h |
Voevolumecontrol |
1. Speaker Volume Control
2. Microphone Volume Control 3. Non-linear voice level control 4. Mute 5. Volume Amplification
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
I. Environment
Refer to the previous article: WEBRTC Learning Three: recording and playback
Two. Implement
The network communication protocol is not explicitly specified in the
Voiceengine, so voice chat is not possible only by calling the Voiceengine API. Voenetwork provides method registerexternaltransport (int channel, transport& Transport), It allows you to specify a user-defined transport protocol transport for the Channel Channnel. So we just need to subclass the transport and implement some kind of communication protocol in the class. Transport class in Transport.h, Transport.h is shown below.
#ifndef webrtc_transport_h_
#define Webrtc_transport_h_
#include <stddef.h>
#include "webrtc/ Typedefs.h "
namespace WebRTC {
//TODO (Holmer): Look to unifying this and the packetoptions in
//Asyncpack Etsocket.h.
struct Packetoptions {
//A-bits positive ID. Negative IDs is invalid and should is interpreted
//as packet_id not being set.
int packet_id =-1;
};
Class Transport {public
:
virtual bool SENDRTP (const uint8_t* packet,
size_t length,
const packetoptions& options) = 0;
virtual bool Sendrtcp (const uint8_t* packet, size_t length) = 0;
Protected:
virtual ~transport () {}
};
} namespace WebRTC
#endif //Webrtc_transport_h_
As long as there are two pure virtual functions in the transport class, we are going to implement them and send the data out by invoking the Send function of the communication protocol in their implementation. It is important to note that RTP and RTCP messages are transmitted over different ports.
Here is my Tranport sub-class Mytransport.
Mytransport.h
#ifndef mytransport_h #define MYTRANSPORT_H #include <QUdpSocket> #include "webrtc/transport.h" using namespace we
BRTC;
Class Mytransport:public qobject,public Transport {q_object public:mytransport ();
~mytransport ();
void Setlocalreceiver (int port);
void Stoprecieve ();
void setsenddestination (QString ip, int port);
void Stopsend (); Transport functions override bool SENDRTP (const uint8_t* packet,size_t length,const packetoptions& options) ove
Rride;
BOOL Sendrtcp (const uint8_t* packet, size_t length) override;
Private:qudpsocket * UDPSOCKETSENDRTP;
Qudpsocket * UDPSOCKETSENDRTCP;
Qudpsocket * UDPSOCKETRECVRTP;
Qudpsocket * UDPSOCKETRECVRTCP;
QString Destip;
int destport;
BOOL Sendflag;
BOOL Recvflag;
Signals:void signalrecvrtpdata (char *data,int length);
void Signalrecvrtcpdata (char *data,int length);
void Signalsendrtpdata (char *data,int length); void Signalsendrtcpdata (char*data,int length);
Private Slots:void slotrtpreadpendingdatagrams ();
void Slotrtcpreadpendingdatagrams ();
void Slotsendrtpdata (char *data,int length);
void Slotsendrtcpdata (char *data,int length);
};
#endif//Mytransport_h
Mytransport.cpp
#include "mytransport.h" #include "Qdebug" Mytransport::mytransport ():d Estip (""), Destport (0), Sendflag (True
), Recvflag (true) {udpsocketsendrtp=new qudpsocket ();
UDPSOCKETRECVRTP = new Qudpsocket ();
Udpsocketsendrtcp=new Qudpsocket ();
Udpsocketrecvrtcp = new Qudpsocket ();
Connect (UDPSOCKETRECVRTP, SIGNAL (Readyread ()), this, SLOT (Slotrtpreadpendingdatagrams ()));
Connect (udpsocketrecvrtcp, SIGNAL (Readyread ()), this, SLOT (Slotrtcpreadpendingdatagrams ()));
Connect (this,signal (signalsendrtpdata (char *,int)), This,slot (Slotsendrtpdata (char *,int));
Connect (this,signal (signalsendrtcpdata (char *,int)), This,slot (Slotsendrtcpdata (char *,int));
} mytransport::~mytransport () {udpsocketsendrtp->deletelater ();
Udpsocketrecvrtp->deletelater ();
Udpsocketsendrtcp->deletelater ();
Udpsocketrecvrtcp->deletelater ();
} void Mytransport::setlocalreceiver (int port) {Udpsocketrecvrtp->bind (port, qudpsocket::shareaddress); Udpsocketrecvrtcp->bind (port+1, qudpsocket::shareaddress);
Recvflag=true;
} void Mytransport::stoprecieve () {udpsocketrecvrtp->abort ();
Udpsocketrecvrtcp->abort ();
Recvflag=false;
} void mytransport::setsenddestination (QString ip, int port) {destip=ip;
Destport=port;
Sendflag=true; } void Mytransport::stopsend () {sendflag=false;}//Why not call Udpsocketsendrtp->writedatagram directly, and use the signal, is because SENDRTP in another line thread bool MYTRANSPORT::SENDRTP (const uint8_t* packet,size_t length,const packetoptions& options) {Q_
UNUSED (options);
if (Sendflag) Emit Signalsendrtpdata ((char*) packet,length);
return true; }//Why not call Udpsocketsendrtcp->writedatagram directly, but with the signal because SENDRTCP is in another line thread bool Mytransport::sendrtcp (const uint8_t*
Packet, size_t length) {if (Sendflag) Emit Signalsendrtcpdata ((char*) packet,length);
return true; } void Mytransport::slotsendrtpdata (char *data,int length) {udpsocketsendrtp->writedatagram (data, Length,qhostadd RessDestip), Destport); The//RTCP port is RTP port +1 void Mytransport::slotsendrtcpdata (char *data,int length) {Udpsocketsendrtcp->writedatagram (da
TA, length,qhostaddress (destip), destport+1);
} void Mytransport::slotrtpreadpendingdatagrams () {Qbytearray datagram; while (Udpsocketrecvrtp->haspendingdatagrams () &&recvflag) {datagram.resize (udpsocketrecvrtp->p
Endingdatagramsize ());
Qhostaddress Sender;
Quint16 Senderport;
int Size=udpsocketrecvrtp->readdatagram (Datagram.data (), Datagram.size (), &sender,
&senderport);
if (size>0) {Emit signalrecvrtpdata (Datagram.data (), datagram.size ());
}}} void Mytransport::slotrtcpreadpendingdatagrams () {Qbytearray datagram; while (Udpsocketrecvrtcp->haspendingdatagrams () &&recvflag) {datagram.resize (udpsocketrecvrtcp->
;p endingdatagramsize ()); QhoStaddress Sender;
Quint16 Senderport;
int Size=udpsocketrecvrtcp->readdatagram (Datagram.data (), Datagram.size (), &sender,
&senderport);
if (size>0) {Emit signalrecvrtcpdata (Datagram.data (), datagram.size ());
}
}
}
Then instantiate the Mytranspot class and pass in Registerexternaltransport (int channel, transport& Transport).
Above is the process of sending data, if you want to receive data, you can pass the data received by Qudpsocket to the Receivedrtppacket and Receivedrtppacket methods in Voenetwork. When you use a custom transport protocol, the data that is received from the network must be passed to both methods.
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> #include <QThread> MainWindow::
MainWindow (Qwidget *parent): Qmainwindow (parent), UI (new Ui::mainwindow), error (0), Audiochannel (0),
Ptrvoengine (NULL), ptrvoebase (null), Ptrvoevolumecontrol (null), ptrvoenetwork (null), Ptrvoehardware (NULL)
{UI->SETUPUI (this);
Creatvoiceengine ();
Initialvoiceengine ();
Setdevice ();
Setchannel ();
Setnetwork (); Connect (ui->horizontalslidermicrophonevolume,signal (valuechanged (int)), This,slot (
Slotsetmicrophonevolumevalue (int))); Connect (ui->horizontalsliderspeakervolume,signal (valuechanged (int)), This,slot (slotsetspeakervolumevalue (int)
)));
int Vol=getmicrophonevolumevalue ();
Ui->horizontalslidermicrophonevolume->setvalue (vol);
Ui->lineeditmicrophonevolumevalue->settext (Qstring::number (vol));
Vol=getspeakervolumevalue (); Ui->horizontalsliderspeakervolume->setvalue (vol.);
Ui->lineeditspeakervolumevalue->settext (Qstring::number (vol));
} mainwindow::~mainwindow () {Delete UI;
Uninitialvoiceengine ();
} void Mainwindow::creatvoiceengine () {ptrvoengine = Voiceengine::create ();
Ptrvoebase = Voebase::getinterface (ptrvoengine);
Ptrvoevolumecontrol = Voevolumecontrol::getinterface (ptrvoengine);
Ptrvoehardware = Voehardware::getinterface (ptrvoengine);
ptrvoenetwork= Voenetwork::getinterface (Ptrvoengine);
} int Mainwindow::initialvoiceengine () {error = Ptrvoebase->init ();
if (Error! = 0) {qdebug () << "error in Voebase::init";
return error;
} error = Ptrvoebase->registervoiceengineobserver (myobserver); if (Error! = 0) {qdebug () << "error in Voebase:;
Registervoiceengineobserver ";
return error;
} Char temp[1024];
Error = ptrvoebase->getversion (temp); if (Error! = 0) {qdebug () << "error in Voebase::getversiOn ";
return error;
} ui->lineeditversion->settext (QString (temp));
return 100;
} int Mainwindow::uninitialvoiceengine () {//stop playout error = ptrvoebase->stopplayout (Audiochannel);
if (Error! = 0) {qdebug () << "error in Voebase::stopplayout";
return error;
}//deregister Error = Ptrvoenetwork->deregisterexternaltransport (Audiochannel);
if (Error! = 0) {qdebug () << "error in Voenetwork::D eregisterexternaltransport";
return error;
}//delete Channel error = Ptrvoebase->deletechannel (Audiochannel);
if (Error! = 0) {qdebug () << "error in Voebase::D Eletechannel";
return error;
}//deregister observer Ptrvoebase->deregistervoiceengineobserver ();
Error = Ptrvoebase->terminate ();
if (Error! = 0) {qdebug () << "error in Voebase::terminate";
return error;
} if (Ptrvoebase) { Ptrvoebase->release ();
} if (Ptrvoevolumecontrol) {ptrvoevolumecontrol->release ();
} if (ptrvoenetwork) {ptrvoenetwork->release ();
} if (Ptrvoehardware) {ptrvoehardware->release ();
BOOL flag = Voiceengine::D elete (Ptrvoengine);
if (!flag) {qdebug () << "ERROR in Voiceengine::D elete";
return-1;
} return 100;
} int Mainwindow::setdevice () {int rnum ( -1), Pnum (-1);
Error = Ptrvoehardware->getnumofrecordingdevices (rnum);
if (Error! = 0) {qdebug () << "error in Voehardware::getnumofrecordingdevices";
return error;
} error = Ptrvoehardware->getnumofplayoutdevices (pnum);
if (Error! = 0) {qdebug () << "error in Voehardware::getnumofplayoutdevices";
return error;
} char name[128] = {0};
Char guid[128] = {0}; for (int j = 0; j < Rnum; ++j) {error = PtrvoehaRdware->getrecordingdevicename (j, name, GUID);
if (Error! = 0) {qdebug () << "error in Voehardware::getrecordingdevicename";
return error;
} ui->comboboxrecordingdevice->additem (QString (name));
} for (int j = 0; j < Pnum; ++j) {error = Ptrvoehardware->getplayoutdevicename (j, name, GUID);
if (Error! = 0) {qdebug () << "error in Voehardware::getplayoutdevicename";
return error;
} ui->comboboxplayoutdevice->additem (QString (name));
} error = Ptrvoehardware->setrecordingdevice (Ui->comboboxrecordingdevice->currentindex ());
if (Error! = 0) {qdebug () << "error in Voehardware::setrecordingdevice";
return error;
} error = Ptrvoehardware->setplayoutdevice (Ui->comboboxplayoutdevice->currentindex ()); if (Error! = 0) {qdebug () << "error in Voehardware::seTplayoutdevice ";
return error;
} return 100;
} void Mainwindow::setchannel () {Audiochannel = Ptrvoebase->createchannel ();
if (Audiochannel < 0) {Qdebug () << "ERROR in Voebase::createchannel";
}//Allow receive error = Ptrvoebase->startreceive (Audiochannel);
if (Error! = 0) {qdebug () << "error in voebase::startreceive";
}//allow playback of error = Ptrvoebase->startplayout (Audiochannel);
if (Error! = 0) {qdebug () << "error in Voebase::startplayout";
}//Allow send error = Ptrvoebase->startsend (Audiochannel);
if (Error! = 0) {qdebug () << "error in voebase::startsend=";
}} void Mainwindow::setnetwork () {mytransport = new mytransport ();
Error = Ptrvoenetwork->registerexternaltransport (Audiochannel,*mytransport);
if (Error! = 0) {qdebug () << "error in Voehardware::registerexternaltransport"; } Connect (mytransport,signal(Signalrecvrtpdata (Char*,int)), This,slot (Slotrecvrtpdata (Char*,int)));
Connect (mytransport,signal (Signalrecvrtcpdata (Char*,int)), This,slot (Slotrecvrtcpdata (Char*,int)));
} int Mainwindow::getmicrophonevolumevalue () {unsigned int vol = 999;
Error = Ptrvoevolumecontrol->getmicvolume (vol);
if (Error! = 0) {qdebug () << "error in Voevolume::getmicvolume";
return 0; } if ((Vol > 255) | |
(Vol < 0))
{qdebug () << "ERROR in Getmicvolume";
return 0;
} return vol;
} int Mainwindow::getspeakervolumevalue () {unsigned int vol = 999;
Error = Ptrvoevolumecontrol->getspeakervolume (vol);
if (Error! = 0) {qdebug () << "error in Voevolume::getspeakervolume";
return 0; } if ((Vol > 255) | |
(Vol < 0))
{qdebug () << "ERROR in Getspeakervolume";
return 0;
} return vol;
} void Mainwindow::slotsetmicrophonevolumevalue (int value) { Error = Ptrvoevolumecontrol->setmicvolume (value);
if (Error! = 0) {qdebug () << "error in Voevolume::setmicvolume";
} else {Ui->lineeditmicrophonevolumevalue->settext (Qstring::number (value));
}} void Mainwindow::slotsetspeakervolumevalue (int value) {error = Ptrvoevolumecontrol->setspeakervolume (value);
if (Error! = 0) {qdebug () << "error in Voevolume::setspeakervolume";
} else {Ui->lineeditspeakervolumevalue->settext (Qstring::number (value)); }} void Mainwindow::slotrecvrtpdata (char *data,int length) {ptrvoenetwork->receivedrtppacket (Audiochannel, data,
Length, Packettime ()); } void Mainwindow::slotrecvrtcpdata (char *data,int length) {ptrvoenetwork->receivedrtcppacket (Audiochannel, data,
length);
} void Mainwindow::on_pushbuttonsend_clicked () {static bool flag=true; if (flag) {mytransport->setsenddestination (ui->lineeditdestip->text (), Ui->lineeditdestport->text (). ToInt ());
Ui->pushbuttonsend->settext (Qstringliteral ("Stop"));
} else {mytransport->stopsend ();
Ui->pushbuttonsend->settext (Qstringliteral ("Start"));
} Flag=!flag;
} void Mainwindow::on_pushbuttonreceive_clicked () {static bool flag=true;
if (flag) {Mytransport->setlocalreceiver (Ui->lineeditlocalport->text (). ToInt ());
Ui->pushbuttonreceive->settext (Qstringliteral ("Stop"));
} else {mytransport->stoprecieve ();
Ui->pushbuttonreceive->settext (Qstringliteral ("Start"));
} Flag=!flag; }
three. Effects
SOURCE Link: See http://blog.csdn.net/caoshangpa/article/details/53889057 's comments