Changeset 329 for pjproject/trunk


Ignore:
Timestamp:
Mar 17, 2006 7:41:19 PM (19 years ago)
Author:
bennylp
Message:

Added comments in simpleua.c

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/samples/simpleua.c

    r328 r329  
    1  
    2 /* Include all PJSIP core headers. */ 
     1/* $Id$ */ 
     2/*  
     3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> 
     4 * 
     5 * This program is free software; you can redistribute it and/or modify 
     6 * it under the terms of the GNU General Public License as published by 
     7 * the Free Software Foundation; either version 2 of the License, or 
     8 * (at your option) any later version. 
     9 * 
     10 * This program is distributed in the hope that it will be useful, 
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     13 * GNU General Public License for more details. 
     14 * 
     15 * You should have received a copy of the GNU General Public License 
     16 * along with this program; if not, write to the Free Software 
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  
     18 */ 
     19 
     20 
     21/** 
     22 * simpleua.c 
     23 * 
     24 * This is a very simple SIP user agent complete with media. The user 
     25 * agent should do a proper SDP negotiation and start RTP media once 
     26 * SDP negotiation has completed. 
     27 * 
     28 * This program does not register to SIP server. 
     29 * 
     30 * Capabilities to be demonstrated here: 
     31 *  - Basic call 
     32 *  - UDP transport at port 5060 (hard coded) 
     33 *  - RTP socket at port 4000 (hard coded) 
     34 *  - proper SDP negotiation 
     35 *  - PCMA/PCMU codec only. 
     36 *  - Audio/media to sound device. 
     37 * 
     38 * 
     39 * Usage: 
     40 *  - To make outgoing call, start simpleua with the URL of remote 
     41 *    destination to contact. 
     42 *    E.g.: 
     43 *       simpleua sip:user@remote 
     44 * 
     45 *  - Incoming calls will automatically be answered with 180, then 200. 
     46 * 
     47 * This program does not disconnect call. 
     48 * 
     49 * This program will quit once it has completed a single call. 
     50 */ 
     51 
     52/* Include all headers. */ 
    353#include <pjsip.h> 
    4  
    5 /* Include all PJMEDIA headers. */ 
    654#include <pjmedia.h> 
    7  
    8 /* Include all PJMEDIA-CODEC headers. */ 
    955#include <pjmedia-codec.h> 
    10  
    11 /* Include all PJSIP-UA headers */ 
    1256#include <pjsip_ua.h> 
    13  
    14 /* Include all PJSIP-SIMPLE headers */ 
    1557#include <pjsip_simple.h> 
    16  
    17 /* Include all PJLIB-UTIL headers. */ 
    1858#include <pjlib-util.h> 
    19  
    20 /* Include all PJLIB headers. */ 
    2159#include <pjlib.h> 
    2260 
    23  
     61/* For logging purpose. */ 
    2462#define THIS_FILE   "simpleua.c" 
    2563 
     
    2866 * Static variables. 
    2967 */ 
    30 static pj_bool_t g_complete; 
    31  
    32 /* Global endpoint instance. */ 
    33 static pjsip_endpoint *g_endpt; 
    34  
    35 /* Global caching pool factory. */ 
    36 static pj_caching_pool cp; 
    37  
    38 /* Global media endpoint. */ 
    39 static pjmedia_endpt        *g_med_endpt; 
    40 static pjmedia_sock_info     g_med_skinfo; 
    41  
    42 /* Call variables. */ 
    43 static pjsip_inv_session    *g_inv; 
    44 static pjmedia_session      *g_med_session; 
    45 static pjmedia_snd_port     *g_snd_player; 
    46 static pjmedia_snd_port     *g_snd_rec; 
     68 
     69static pj_bool_t             g_complete;    /* Quit flag.               */ 
     70static pjsip_endpoint       *g_endpt;       /* SIP endpoint.            */ 
     71static pj_caching_pool       cp;            /* Global pool factory.     */ 
     72 
     73static pjmedia_endpt        *g_med_endpt;   /* Media endpoint.          */ 
     74static pjmedia_sock_info     g_med_skinfo;  /* Socket info for media    */ 
     75 
     76/* Call variables: */ 
     77static pjsip_inv_session    *g_inv;         /* Current invite session.  */ 
     78static pjmedia_session      *g_med_session; /* Call's media session.    */ 
     79static pjmedia_snd_port     *g_snd_player;  /* Call's sound player      */ 
     80static pjmedia_snd_port     *g_snd_rec;     /* Call's sound recorder.   */ 
    4781 
    4882 
    4983/* 
    50  * Prototypes. 
    51  */ 
     84 * Prototypes: 
     85 */ 
     86 
     87/* Callback to be called when SDP negotiation is done in the call: */ 
    5288static void call_on_media_update( pjsip_inv_session *inv, 
    5389                                  pj_status_t status); 
     90 
     91/* Callback to be called when invite session's state has changed: */ 
    5492static void call_on_state_changed( pjsip_inv_session *inv,  
    5593                                   pjsip_event *e); 
     94 
     95/* Callback to be called when dialog has forked: */ 
    5696static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e); 
     97 
     98/* Callback to be called to handle incoming requests outside dialogs: */ 
    5799static pj_bool_t on_rx_request( pjsip_rx_data *rdata ); 
    58100 
    59101 
    60 /* Module to receive incoming requests (e.g. INVITE). */ 
     102 
     103 
     104/* This is a PJSIP module to be registered by application to handle 
     105 * incoming requests outside any dialogs/transactions. The main purpose 
     106 * here is to handle incoming INVITE request message, where we will 
     107 * create a dialog and INVITE session for it. 
     108 */ 
    61109static pjsip_module mod_simpleua = 
    62110{ 
     
    78126 
    79127/*  
    80  * Show error. 
     128 * Util to display the error message for the specified error code   
    81129 */ 
    82130static int app_perror( const char *sender, const char *title,  
     
    94142/* 
    95143 * main() 
     144 * 
     145 * If called with argument, treat argument as SIP URL to be called. 
     146 * Otherwise wait for incoming calls. 
    96147 */ 
    97148int main(int argc, char *argv[]) 
     
    99150    pj_status_t status; 
    100151 
    101     /* Init PJLIB */ 
     152    /* Must init PJLIB first: */ 
    102153    status = pj_init(); 
    103154    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    104155 
    105     /* Init PJLIB-UTIL: */ 
     156 
     157    /* Then init PJLIB-UTIL: */ 
    106158    status = pjlib_util_init(); 
    107159    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    108160 
    109161 
    110     /* Init memory pool: */ 
    111  
    112     /* Init caching pool. */ 
     162    /* Must create a pool factory before we can allocate any memory. */ 
    113163    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); 
     164 
    114165 
    115166    /* Create global endpoint: */ 
     
    133184    } 
    134185 
    135     /*  
    136      * Add UDP transport.  
     186 
     187    /*  
     188     * Add UDP transport, with hard-coded port  
     189     * Alternatively, application can use pjsip_udp_transport_attach() to 
     190     * start UDP transport, if it already has an UDP socket (e.g. after it 
     191     * resolves the address with STUN). 
    137192     */ 
    138193    { 
     
    152207 
    153208    /*  
    154      * Init transaction layer.  
     209     * Init transaction layer. 
     210     * This will create/initialize transaction hash tables etc. 
    155211     */ 
    156212    status = pjsip_tsx_layer_init_module(g_endpt); 
    157213    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    158214 
    159     /*  
    160      * Initialize UA layer module:  
     215 
     216    /*  
     217     * Initialize UA layer module. 
     218     * This will create/initialize dialog hash tables etc. 
    161219     */ 
    162220    status = pjsip_ua_init_module( g_endpt, NULL ); 
    163221    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    164222 
    165     /* 
     223 
     224    /*  
    166225     * Init invite session module. 
     226     * The invite session module initialization takes additional argument, 
     227     * i.e. a structure containing callbacks to be called on specific 
     228     * occurence of events. 
     229     * 
     230     * The on_state_changed and on_new_session callbacks are mandatory. 
     231     * Application must supply the callback function. 
     232     * 
     233     * We use on_media_update() callback in this application to start 
     234     * media transmission. 
    167235     */ 
    168236    { 
     
    182250 
    183251    /* 
    184      * Register module to receive incoming requests. 
     252     * Register our module to receive incoming requests. 
    185253     */ 
    186254    status = pjsip_endpt_register_module( g_endpt, &mod_simpleua); 
     
    189257 
    190258    /*  
    191      * Init media endpoint:  
     259     * Initialize media endpoint. 
     260     * This will implicitly initialize PJMEDIA too. 
    192261     */ 
    193262    status = pjmedia_endpt_create(&cp.factory, &g_med_endpt); 
     
    202271    /*  
    203272     * Initialize RTP socket info for the media. 
     273     * The RTP socket is hard-codec to port 4000. 
    204274     */ 
    205275    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &g_med_skinfo.rtp_sock); 
     
    250320        } 
    251321 
    252         /* Get media capability from media endpoint: */ 
    253         status = pjmedia_endpt_create_sdp( g_med_endpt, dlg->pool, 1,  
    254                                            &g_med_skinfo, &local_sdp); 
     322        /* Get the SDP body to be put in the outgoing INVITE, by asking 
     323         * media endpoint to create one for us. The SDP will contain all 
     324         * codecs that have been registered to it (in this case, only 
     325         * PCMA and PCMU), plus telephony event. 
     326         */ 
     327        status = pjmedia_endpt_create_sdp( g_med_endpt,     /* the media endpt  */ 
     328                                           dlg->pool,       /* pool.            */ 
     329                                           1,               /* # of streams     */ 
     330                                           &g_med_skinfo,   /* RTP sock info    */ 
     331                                           &local_sdp);     /* the SDP result   */ 
    255332        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    256333 
    257334 
    258         /* Create the INVITE session: */ 
     335 
     336        /* Create the INVITE session, and pass the SDP returned earlier 
     337         * as the session's initial capability. 
     338         */ 
    259339        status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv); 
    260340        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    261341 
    262342 
    263         /* Create initial INVITE request: */ 
     343 
     344        /* Create initial INVITE request. 
     345         * This INVITE request will contain a perfectly good request and  
     346         * an SDP body as well. 
     347         */ 
    264348        status = pjsip_inv_invite(g_inv, &tdata); 
    265349        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    266350 
    267         /* Send initial INVITE request: */ 
     351 
     352 
     353        /* Send initial INVITE request.  
     354         * From now on, the invite session's state will be reported to us 
     355         * via the invite session callbacks. 
     356         */ 
    268357        status = pjsip_inv_send_msg(g_inv, tdata); 
    269358        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 
    270359 
     360 
    271361    } else { 
     362 
     363        /* No URL to make call to */ 
     364 
    272365        PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls...")); 
    273366    } 
     
    287380/* 
    288381 * Callback when INVITE session state has changed. 
     382 * This callback is registered when the invite session module is initialized. 
     383 * We mostly want to know when the invite session has been disconnected, 
     384 * so that we can quit the application. 
    289385 */ 
    290386static void call_on_state_changed( pjsip_inv_session *inv,  
     
    308404} 
    309405 
     406 
     407/* This callback is called when dialog has forked. */ 
     408static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e) 
     409{ 
     410    /* To be done... */ 
     411} 
     412 
     413 
    310414/* 
    311  * Callback when media negotiation has completed. 
     415 * Callback when incoming requests outside any transactions and any 
     416 * dialogs are received. We're only interested to hande incoming INVITE 
     417 * request, and we'll reject any other requests with 500 response. 
     418 */ 
     419static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) 
     420{ 
     421    pjsip_dialog *dlg; 
     422    pjmedia_sdp_session *local_sdp; 
     423    pjsip_tx_data *tdata; 
     424    unsigned options = 0; 
     425    pj_status_t status; 
     426 
     427 
     428    /*  
     429     * Respond (statelessly) any non-INVITE requests with 500  
     430     */ 
     431    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { 
     432 
     433        pj_str_t reason = pj_str("Simple UA unable to handle this request"); 
     434 
     435        pjsip_endpt_respond_stateless( g_endpt, rdata,  
     436                                       500, &reason, 
     437                                       NULL, NULL); 
     438        return PJ_TRUE; 
     439    } 
     440 
     441 
     442    /* 
     443     * Reject INVITE if we already have an INVITE session in progress. 
     444     */ 
     445    if (g_inv) { 
     446 
     447        pj_str_t reason = pj_str("Another call is in progress"); 
     448 
     449        pjsip_endpt_respond_stateless( g_endpt, rdata,  
     450                                       500, &reason, 
     451                                       NULL, NULL); 
     452        return PJ_TRUE; 
     453 
     454    } 
     455 
     456    /* Verify that we can handle the request. */ 
     457    status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, 
     458                                      g_endpt, NULL); 
     459    if (status != PJ_SUCCESS) { 
     460 
     461        pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE"); 
     462 
     463        pjsip_endpt_respond_stateless( g_endpt, rdata,  
     464                                       500, &reason, 
     465                                       NULL, NULL); 
     466        return PJ_TRUE; 
     467    }  
     468 
     469    /* 
     470     * Create UAS dialog. 
     471     */ 
     472    status = pjsip_dlg_create_uas( pjsip_ua_instance(),  
     473                                   rdata, 
     474                                   NULL, /* contact */ 
     475                                   &dlg); 
     476    if (status != PJ_SUCCESS) { 
     477        pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL, 
     478                                      NULL, NULL); 
     479        return PJ_TRUE; 
     480    } 
     481 
     482    /*  
     483     * Get media capability from media endpoint:  
     484     */ 
     485 
     486    status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1, 
     487                                       &g_med_skinfo,  
     488                                       &local_sdp); 
     489    PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
     490 
     491 
     492    /*  
     493     * Create invite session, and pass both the UAS dialog and the SDP 
     494     * capability to the session. 
     495     */ 
     496    status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv); 
     497    PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
     498 
     499 
     500    /* 
     501     * Initially send 180 response. 
     502     * 
     503     * The very first response to an INVITE must be created with 
     504     * pjsip_inv_initial_answer(). Subsequent responses to the same 
     505     * transaction MUST use pjsip_inv_answer(). 
     506     */ 
     507    status = pjsip_inv_initial_answer(g_inv, rdata,  
     508                                      180,  
     509                                      NULL, NULL, &tdata); 
     510    PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
     511 
     512 
     513    /* Send the 180 response. */   
     514    status = pjsip_inv_send_msg(g_inv, tdata);  
     515    PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
     516 
     517 
     518    /* 
     519     * Now create 200 response. 
     520     */ 
     521    status = pjsip_inv_answer( g_inv,  
     522                               200, NULL,       /* st_code and st_text */ 
     523                               NULL,            /* SDP already specified */ 
     524                               &tdata); 
     525    PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
     526 
     527    /* 
     528     * Send the 200 response. 
     529     */ 
     530    status = pjsip_inv_send_msg(g_inv, tdata); 
     531    PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
     532 
     533 
     534    /* Done.  
     535     * When the call is disconnected, it will be reported via the callback. 
     536     */ 
     537 
     538    return PJ_TRUE; 
     539} 
     540 
     541  
     542 
     543/* 
     544 * Callback when SDP negotiation has completed. 
     545 * We are interested with this callback because we want to start media 
     546 * as soon as SDP negotiation is completed. 
    312547 */ 
    313548static void call_on_media_update( pjsip_inv_session *inv, 
     
    328563    } 
    329564 
    330     /* Get local and remote SDP */ 
    331  
     565    /* Get local and remote SDP. 
     566     * We need both SDPs to create a media session. 
     567     */ 
    332568    status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); 
    333569 
    334570    status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); 
    335571 
    336     /* Create new media session.  
     572 
     573    /* Create new media session, passing the two SDPs, and also the 
     574     * media socket that we created earlier. 
    337575     * The media session is active immediately. 
    338576     */ 
     
    346584    } 
    347585 
    348     /* Get the port interface of the first stream in the session. */ 
     586 
     587    /* Get the media port interface of the first stream in the session.  
     588     * Media port interface is basicly a struct containing get_frame() and 
     589     * put_frame() function. With this media port interface, we can attach 
     590     * the port interface to conference bridge, or directly to a sound 
     591     * player/recorder device. 
     592     */ 
    349593    pjmedia_session_get_port(g_med_session, 0, &media_port); 
     594 
     595 
    350596 
    351597    /* Create a sound Player device and connect the media port to the 
     
    398644 
    399645 
    400 /* 
    401  * This callback is called when dialog has forked 
    402  */ 
    403 static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e) 
    404 { 
    405 } 
    406  
    407 /* 
    408  * Callback when incoming requests outside any transactions and any 
    409  * dialogs are received 
    410  */ 
    411 static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) 
    412 { 
    413     pjsip_dialog *dlg; 
    414     pjmedia_sdp_session *local_sdp; 
    415     pjsip_tx_data *tdata; 
    416     unsigned options = 0; 
    417     pj_status_t status; 
    418  
    419     /*  
    420      * Respond (statelessly) any non-INVITE requests with 500  
    421      */ 
    422     if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { 
    423  
    424         pj_str_t reason = pj_str("Simple UA unable to handle this request"); 
    425  
    426         pjsip_endpt_respond_stateless( g_endpt, rdata,  
    427                                        500, &reason, 
    428                                        NULL, NULL); 
    429         return PJ_TRUE; 
    430     } 
    431  
    432     /* 
    433      * Reject INVITE if we already have an INVITE session in progress. 
    434      */ 
    435     if (g_inv) { 
    436  
    437         pj_str_t reason = pj_str("Another call is in progress"); 
    438  
    439         pjsip_endpt_respond_stateless( g_endpt, rdata,  
    440                                        500, &reason, 
    441                                        NULL, NULL); 
    442         return PJ_TRUE; 
    443  
    444     } 
    445  
    446     /* Verify that we can handle the request. */ 
    447     status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, 
    448                                       g_endpt, NULL); 
    449     if (status != PJ_SUCCESS) { 
    450  
    451         pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE"); 
    452  
    453         pjsip_endpt_respond_stateless( g_endpt, rdata,  
    454                                        500, &reason, 
    455                                        NULL, NULL); 
    456         return PJ_TRUE; 
    457     }  
    458  
    459     /* 
    460      * Create UAS dialog. 
    461      */ 
    462     status = pjsip_dlg_create_uas( pjsip_ua_instance(),  
    463                                    rdata, 
    464                                    NULL, /* contact */ 
    465                                    &dlg); 
    466     if (status != PJ_SUCCESS) { 
    467         pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL, 
    468                                       NULL, NULL); 
    469         return PJ_TRUE; 
    470     } 
    471  
    472     /*  
    473      * Get media capability from media endpoint:  
    474      */ 
    475  
    476     status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1, 
    477                                        &g_med_skinfo,  
    478                                        &local_sdp); 
    479     PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
    480  
    481     /*  
    482      * Create invite session:  
    483      */ 
    484     status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv); 
    485     PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
    486  
    487     /* 
    488      * Initially send 180 response. 
    489      */ 
    490     status = pjsip_inv_initial_answer(g_inv, rdata,  
    491                                       180,  
    492                                       NULL, NULL, &tdata); 
    493     PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
    494  
    495     /* 
    496      * Send the 180 response. 
    497      */   
    498     status = pjsip_inv_send_msg(g_inv, tdata);  
    499     PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
    500  
    501     /* 
    502      * Now send 200 response. 
    503      */ 
    504     status = pjsip_inv_answer( g_inv,  
    505                                200, NULL,       /* st_code and st_text */ 
    506                                NULL,            /* SDP already specified */ 
    507                                &tdata); 
    508     PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
    509  
    510     /* 
    511      * Send the 200 response. 
    512      */ 
    513     status = pjsip_inv_send_msg(g_inv, tdata); 
    514     PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); 
    515  
    516     return PJ_TRUE; 
    517 } 
    518  
    519   
Note: See TracChangeset for help on using the changeset viewer.