And we decided to make friends with Baresip and Nodejs

    What is Baresip? As stated on the project website, it is a cross-platform, modular SIP agent with support for audio and video.

    And where does nodejs have to do with it? Yes, it turned out that in a large project written in nodejs and using Freeswitch and its portaudio module, in connection with the incorrect operation of the latter, it was necessary to implement another sip client for audio calls.

    The choice during a technical meeting of one of our developers with Google fell on Baresip.


    Main goals:


    • Call management (call, hang up, answer, etc.)
    • Receiving events (incoming call, call ended, phoned, etc.)
    • Obtaining information about the status of the client (call list, etc.)

    The result was a small npm module node_baresip

    Link to the baresip page

    Api search


    Since the baresip console utility, I decided that there probably is either a library or some way of interacting with the running application.
    And I was right but not completely :)

    As it turned out in baresip, everything is tied to text commands and they can be entered via:
    • console
    • get http request parameter
    • UDP / TCP connection

    Real hardcore api :)

    For the first implementation, I chose http.

    Node_baresip implementation


    Sending commands will look like this:
    Call in the console
    d sip:user@domain.com

    Call via http
    http://127.0.0.1:8000/?duser@domain.com


    Baresiphttpwrapper.js was written with a generic interface:
    • getCallList
    • dial
    • hangup
    • answer
    • muteUnmute
    • hold
    • resume



    Later, you can either write a normal api and make another wrapper, or wait for someone to write it and rewrite wrapper :) Next, the main file of the baresip.js module is implemented.

    To track the status, you have to request a call list every 2 seconds and determine which calls are old, which were are sure which outgoing calls have been received and which incoming ones and give out the corresponding events:
    The code
    self.intervalObject = setInterval( function(){
                self.baresipWrapper.getCallList( function( err, callList){
    				if( err){
                        console.log( "Error get call list:", err, config);
                        var callList = [];
                    }
    				var esatblishedCalls = self.findEsatblishedCalls( callList);
    				var newCalls = self.findNewCalls( callList);
    				var deleteCalls = self.findDeletedCalls( callList);
                    for (var i in newCalls){
                        // ADD CALL
                        self.callList[newCalls[i].sip] = newCalls[i];
                        self.callList[newCalls[i].sip].id = self.generateCallId();
                        self.emit( "new_call", self.callList[newCalls[i].sip]);
                        if( newCalls[i].status == "INCOMING") {
                            self.emit("incoming_call", newCalls[i]);
                        }
                        else if( newCalls[i].status == "ESTABLISHED"){
                            self.emit( "established_call", self.callList[newCalls[i].sip]);
                        }
                    }
                    for (var i in deleteCalls){
                        delete self.callList[deleteCalls[i].sip];
                        self.emit( "end_call", deleteCalls[i]);
                    }
                    for( var i in esatblishedCalls) {
                        self.callList[esatblishedCalls[i].sip].status = "ESTABLISHED";
                        self.emit( "established_call", esatblishedCalls[i]);
                    }
    			});
    		}, self.callListMonitorTimeout);
    


    Events
    • new_call
    • established_call
    • end_call

    The control interface I made is almost the same as in the wrapper
    • getCurrentCalls
    • dial
    • hangup
    • answer
    • muteUnmute
    • hold
    • resume


    Fun surprises baresip


    • As it turned out in baresip, the call does not have any identifier, therefore it is impossible to manage it.
      All management is done only on the last call added to the b-list of calls to baresip. It comes to the point that when an incoming call arrives and there is already an active button, you can only manage the incoming one and the active one cannot even be put on hold.
    • At the same time, as many calls as you like can be active, there is no automatic setting of an active call on hold when answering a new incoming call, and there is not even the option to optionally set this in the config.
    • You can make any number of calls to the same subscriber.


    If the last 2 can be solved by simple checks, then the first one took a certain amount of time.
    At first, I tried to enter a call identifier in the baresip code to be able to control any call via api, but since I know C, I could not implement a cross-platform code that can generate unique identifiers.
    A simpler decision was made. I added the command for setting the previous call to hold, it was even added to the baresip code itself. This minor revision solved the problems and did not have to go further.

    Impressions


    Baresip itself turned out to be a very reliable cross-platform sip agent with a large set of codecs and various modules, only the interaction interface pumped up :)

    PS:
    Finally, we added the setting of an active call on hold before answering an incoming one :)
    github.com/alfredh/baresip/commit/ 25225de72f2ba6c89abe862e2e027906c9ef8a76

    Also popular now: