WEBRTC Learning Four: the simplest voice chat

Source: Internet
Author: User
Tags bind bool emit int size

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-&gt
          ;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-&GT;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


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.