Search code examples
iospjsip

PJSIP for iOS - can not figure out how commands are sent in pjsua app for iOS


I have compiled pjsip following this link and everything works great when I run pjsip sample application for iPhone, ipjsua. Now what is the problem is that I can not understand how commands are sent. I mean, when I type in that Command text field some text somebody is listening what I am writing there and it is executed. Who is this somebody and where it is in the ipjsua app code?

In my application I will not have that text field to write commands. I will have a list of contacts and on contact select I will make my sip call.

Which pjsip function to use to execute command and which function (event, delegate) to listen sip server's response?


Solution

  • Ok, I found the solution.

    Place where commands are send to sip server for ipjsua app is in the char * getInput(char *s, int n, FILE *stream) function in ipjsuaAppDelegate.m file.

    This piece of code in char * getInput(char *s, int n, FILE *stream)

    if (stream != stdin)
    {
        return fgets(s, n, stream);
    }
    

    is reading config.cfg file and its content and it is sent to sip server for execution. In this file you can put any settings for account configurations, media configurations ... (more on this link pjsua manual).

    After config.cfg file is read, this piece of code

    while (!thread_quit && !app.mainView.hasInput)
    {
        int ctr = 0;
        [NSThread sleepForTimeInterval:SLEEP_INTERVAL];
        if (ctr == 4)
        {
          [app performSelectorOnMainThread:@selector(displayMsg:) withObject:mstr waitUntilDone:YES];
            [mstr setString:@""];
            ctr = 0;
        }
        ctr++;
    }
    

    is running and waiting for more commands inputs from application. To trigger this while loop to continue executing you have to set app.mainView.hasInput to true. When you want to send some command:

    • first, you put command text in this variable app.mainView.text
    • second, set app.mainview.hasInput = true

    Of course you can make these variables as private in ipjsuaAppDelegate class.The important fact is that while (!thread_quit && !app.mainView.hasInput) contains instead app.mainView.hasInput your local variable hasInput.

    After sending command , this piece of code is executed (inside of char * getInput(char *s, int n, FILE *stream) function)

    [app.mainView.text getCString:s maxLength:n encoding:NSASCIIStringEncoding];
    [app.mainView.textField setEnabled: false];    
    [app performSelectorOnMainThread:@selector(displayMsg:) withObject:app.mainView.text waitUntilDone:NO];
    
    return s;
    

    Then, corresponding code in pjsua_app.c file is executed and after that function char * getInput(char *s, int n, FILE *stream) is called again and while loop (while (!thread_quit && !app.mainView.hasInput)) is executed and waiting for another input. So, here you can use the moment before while loop execution to send another command if you need to execute two or more consecutive commands (example: For making call you have to send 'm' and after send sip uri to call 'sip:[email protected]' and these are two consecutive commands).

    In my application, it looks something like this

    char * getInput(char *s, int n, FILE *stream)
    {
        if (stream != stdin)
        {
            return fgets(s, n, stream);
        }
    
        [appDelegate performSelectorOnMainThread:@selector(actionAfterCommand) withObject:nil waitUntilDone:NO];   
    
        app.mainView.hasInput = false;
        [app.mainView.textField setEnabled: true];
        [app performSelectorOnMainThread:@selector(displayMsg:) withObject:mstr waitUntilDone:YES];
        [mstr setString:@""];
    
        while (!thread_quit && !app.mainView.hasInput)
        {
            int ctr = 0;
            [NSThread sleepForTimeInterval:SLEEP_INTERVAL];
            if (ctr == 4)
            {
                [app performSelectorOnMainThread:@selector(displayMsg:) withObject:mstr waitUntilDone:YES];
                [mstr setString:@""];
                ctr = 0;
            }
    
            ctr++;
        }
    
        [app.mainView.text getCString:s maxLength:n encoding:NSASCIIStringEncoding];
        [app.mainView.textField setEnabled: false];    
        [app performSelectorOnMainThread:@selector(displayMsg:) withObject:app.mainView.text waitUntilDone:NO];
    
        return s;
    }
    

    and selector actionAfterCommand

    - (void)actionAfterCommand
    {
        [NSThread sleepForTimeInterval:1.0];//this is just to be sure that sip server is ready to listen agin
    
        if ([app.mainView.text isEqualToString:command])// command can be m, a, ...
        {
            app.mainView.text = secondCommand;
            appDelegate.hasInput = true;
        }
    }
    

    Also, if someone have some other approach to this problem, please add it here.