WebRTC

medooze源码分析--启动服务器

2018-11-15  本文已影响212人  音视频直播技术专家

createEndpoint

当我们打开index.js 后,看到的第一个重要的 API就是createEndpoint函数了。我们就以这个 API为开头,一步一步的分析一下medooze的运行机制。

createEndpoint函数定义在 medooze-media-server 库中的 lib 目录下的 MediaServer.js 中。代码如下:

/**
 * Create a new endpoint object
 * @memberof MediaServer
 * @param {String} ip   - External IP address of server, to be used when announcing the local ICE candidate
 * @returns {Endpoint} The new created endpoing
 */
MediaServer.createEndpoint = function(ip)
{
        //Cretate new rtp endpoint
        return new Endpoint(ip);
};

它的作用是公布 ICE 本地候选者,当做一个终端。

顺着这个函数我们继续往下看,在该函数中会创建一个 Endpoint 对象。

Endpoint

medooze-media-server 库中的 lib 目录下的 Endpoint.js 文件是 Endpoint 的类文件。该类的作用如下:

/**
 * An endpoint represent an UDP server socket.
 * The endpoint will process STUN requests in order to be able to associate the remote ip:port with the registered transport and forward any further data comming from that transport.
 * Being a server it is ICE-lite.
 */
/**
 *endpoint 表示UDP服务器套接字。
 *endpoint 将处理STUN请求,以便能够将远程ip:port与注册的传输相关联,并转发来自该传输的任何进一步的通信数据。
 *作为一个服务器,它是轻量级的ICE。
*/

在创建 Endpoint 对象时,会调用它的构造函数。其代码如下:

constructor(ip)
 {
     //Store ip address of the endpoint
     this.ip = ip;
     //Create native endpoint
     this.bundle = new Native.RTPBundleTransport();
     //Start it
     this.bundle.Init();
     //Store all transports
     this.transports = new Set();
     //Create candidate
     this.candidate = new CandidateInfo("1", 1, "UDP", 33554431, ip, this.bundle.GetLocalPort(), "host");
     //Get fingerprint (global at media server level currently)
     this.fingerprint = Native.MediaServer.GetFingerprint().toString();
}

通过上面的代码可以看到 Endpoint 包括以下几个成员:

接下来,我们分别看一下 Native.RTPBundleTransport 和 CandidateInfo。

RTPBundleTransport

RTPBundleTransport 类定义在 media-server 中的 include/RTPBundleTransport.h文件中。该类的构造函数如下:

RTPBundleTransport::RTPBundleTransport()
{
        //Init values
        socket = FD_INVALID;
        port = 0;
        
        //No thread
        setZeroThread(&thread);
        running = false;
        //Mutex
        pthread_mutex_init(&mutex,0);
        pthread_cond_init(&cond,0);
}

Endpoint 类的构函数中,首先创建了 RTPBundleTransport对象,然后又调用了该对象的 Init方法,其代码如下:

int RTPBundleTransport::Init()
{
        int retries = 0;

        sockaddr_in recAddr;

        //Clear addr
        memset(&recAddr,0,sizeof(struct sockaddr_in));
        //Init ramdon
        srand (time(NULL));

        //Set family
        recAddr.sin_family      = AF_INET;

        //Get two consecutive ramdom ports
        while (retries++<100)
        {
                ...

                //Create new sockets
                socket = ::socket(PF_INET,SOCK_DGRAM,0);
                //Get random
                port = (RTPTransport::GetMinPort()+(RTPTransport::GetMaxPort()-RTPTransport::GetMinPort())*double(rand()/double(RAND_MAX)));
                //Make even
                port &= 0xFFFFFFFE;
                //Try to bind to port
                recAddr.sin_port = htons(port);
                //Bind the rtp socket
                if(bind(socket,(struct sockaddr *)&recAddr,sizeof(struct sockaddr_in))!=0)
                        //Try again
                        continue;

                ...
                Start();
                //Done
                Log("<RTPBundleTransport::Init()\n");
                //Opened
                return port;
        }

        //Error
        Error("-RTPBundleTransport::Init() | too many failed attemps opening sockets\n");

        //Failed
        return 0;
}

通过上面的代码我们可以看到, 在Init函数中,主要做了两件事儿:

CandidateInfo

在另外一个称为 semantic-sdp-js的项目中的lib中可以找到 CandidateInfo 类的定义。其构造函数如下:

/**
* CanditateInfo constructor
* @constructor
* @alias CandidateInfo
* @param {String} foundation
* @param {Number} componentId
* @param {String} transport
* @param {Number} priority
* @param {String} address
* @param {Number} port
* @param {String} type
* @param {String} relAddr
* @param {String} relPort
*/
constructor(foundation, componentId, transport, priority, address, port, type, relAddr, relPort) {
    this.foundation         = foundation;
    this.componentId        = componentId;
    this.transport          = transport;
    this.priority           = priority;
    this.address            = address;
    this.port               = port;
    this.type               = type;
    this.relAddr            = relAddr;
    this.relPort            = relPort;
}

其代码非常简单,就是将传入的一些参数保存起来。

小结

上一篇下一篇

猜你喜欢

热点阅读