Changeset 329 for pjproject/trunk
- Timestamp:
- Mar 17, 2006 7:41:19 PM (19 years ago)
- 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. */ 3 53 #include <pjsip.h> 4 5 /* Include all PJMEDIA headers. */6 54 #include <pjmedia.h> 7 8 /* Include all PJMEDIA-CODEC headers. */9 55 #include <pjmedia-codec.h> 10 11 /* Include all PJSIP-UA headers */12 56 #include <pjsip_ua.h> 13 14 /* Include all PJSIP-SIMPLE headers */15 57 #include <pjsip_simple.h> 16 17 /* Include all PJLIB-UTIL headers. */18 58 #include <pjlib-util.h> 19 20 /* Include all PJLIB headers. */21 59 #include <pjlib.h> 22 60 23 61 /* For logging purpose. */ 24 62 #define THIS_FILE "simpleua.c" 25 63 … … 28 66 * Static variables. 29 67 */ 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 69 static pj_bool_t g_complete; /* Quit flag. */ 70 static pjsip_endpoint *g_endpt; /* SIP endpoint. */ 71 static pj_caching_pool cp; /* Global pool factory. */ 72 73 static pjmedia_endpt *g_med_endpt; /* Media endpoint. */ 74 static pjmedia_sock_info g_med_skinfo; /* Socket info for media */ 75 76 /* Call variables: */ 77 static pjsip_inv_session *g_inv; /* Current invite session. */ 78 static pjmedia_session *g_med_session; /* Call's media session. */ 79 static pjmedia_snd_port *g_snd_player; /* Call's sound player */ 80 static pjmedia_snd_port *g_snd_rec; /* Call's sound recorder. */ 47 81 48 82 49 83 /* 50 * Prototypes. 51 */ 84 * Prototypes: 85 */ 86 87 /* Callback to be called when SDP negotiation is done in the call: */ 52 88 static void call_on_media_update( pjsip_inv_session *inv, 53 89 pj_status_t status); 90 91 /* Callback to be called when invite session's state has changed: */ 54 92 static void call_on_state_changed( pjsip_inv_session *inv, 55 93 pjsip_event *e); 94 95 /* Callback to be called when dialog has forked: */ 56 96 static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e); 97 98 /* Callback to be called to handle incoming requests outside dialogs: */ 57 99 static pj_bool_t on_rx_request( pjsip_rx_data *rdata ); 58 100 59 101 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 */ 61 109 static pjsip_module mod_simpleua = 62 110 { … … 78 126 79 127 /* 80 * Show error.128 * Util to display the error message for the specified error code 81 129 */ 82 130 static int app_perror( const char *sender, const char *title, … … 94 142 /* 95 143 * main() 144 * 145 * If called with argument, treat argument as SIP URL to be called. 146 * Otherwise wait for incoming calls. 96 147 */ 97 148 int main(int argc, char *argv[]) … … 99 150 pj_status_t status; 100 151 101 /* Init PJLIB*/152 /* Must init PJLIB first: */ 102 153 status = pj_init(); 103 154 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 104 155 105 /* Init PJLIB-UTIL: */ 156 157 /* Then init PJLIB-UTIL: */ 106 158 status = pjlib_util_init(); 107 159 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 108 160 109 161 110 /* Init memory pool: */ 111 112 /* Init caching pool. */ 162 /* Must create a pool factory before we can allocate any memory. */ 113 163 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); 164 114 165 115 166 /* Create global endpoint: */ … … 133 184 } 134 185 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). 137 192 */ 138 193 { … … 152 207 153 208 /* 154 * Init transaction layer. 209 * Init transaction layer. 210 * This will create/initialize transaction hash tables etc. 155 211 */ 156 212 status = pjsip_tsx_layer_init_module(g_endpt); 157 213 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 158 214 159 /* 160 * Initialize UA layer module: 215 216 /* 217 * Initialize UA layer module. 218 * This will create/initialize dialog hash tables etc. 161 219 */ 162 220 status = pjsip_ua_init_module( g_endpt, NULL ); 163 221 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 164 222 165 /* 223 224 /* 166 225 * 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. 167 235 */ 168 236 { … … 182 250 183 251 /* 184 * Register module to receive incoming requests.252 * Register our module to receive incoming requests. 185 253 */ 186 254 status = pjsip_endpt_register_module( g_endpt, &mod_simpleua); … … 189 257 190 258 /* 191 * Init media endpoint: 259 * Initialize media endpoint. 260 * This will implicitly initialize PJMEDIA too. 192 261 */ 193 262 status = pjmedia_endpt_create(&cp.factory, &g_med_endpt); … … 202 271 /* 203 272 * Initialize RTP socket info for the media. 273 * The RTP socket is hard-codec to port 4000. 204 274 */ 205 275 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &g_med_skinfo.rtp_sock); … … 250 320 } 251 321 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 */ 255 332 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 256 333 257 334 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 */ 259 339 status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv); 260 340 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 261 341 262 342 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 */ 264 348 status = pjsip_inv_invite(g_inv, &tdata); 265 349 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 266 350 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 */ 268 357 status = pjsip_inv_send_msg(g_inv, tdata); 269 358 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); 270 359 360 271 361 } else { 362 363 /* No URL to make call to */ 364 272 365 PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls...")); 273 366 } … … 287 380 /* 288 381 * 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. 289 385 */ 290 386 static void call_on_state_changed( pjsip_inv_session *inv, … … 308 404 } 309 405 406 407 /* This callback is called when dialog has forked. */ 408 static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e) 409 { 410 /* To be done... */ 411 } 412 413 310 414 /* 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 */ 419 static 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. 312 547 */ 313 548 static void call_on_media_update( pjsip_inv_session *inv, … … 328 563 } 329 564 330 /* Get local and remote SDP */ 331 565 /* Get local and remote SDP. 566 * We need both SDPs to create a media session. 567 */ 332 568 status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); 333 569 334 570 status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); 335 571 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. 337 575 * The media session is active immediately. 338 576 */ … … 346 584 } 347 585 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 */ 349 593 pjmedia_session_get_port(g_med_session, 0, &media_port); 594 595 350 596 351 597 /* Create a sound Player device and connect the media port to the … … 398 644 399 645 400 /*401 * This callback is called when dialog has forked402 */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 any409 * dialogs are received410 */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 500421 */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.