📄 simpleua.c
字号:
* Note that Route URI SHOULD have an ";lr" parameter! */ /* Get the SDP body to be put in the outgoing INVITE, by asking * media endpoint to create one for us. The SDP will contain all * codecs that have been registered to it (in this case, only * PCMA and PCMU), plus telephony event. */ status = pjmedia_endpt_create_sdp( g_med_endpt, /* the media endpt */ dlg->pool, /* pool. */ 1, /* # of streams */ &g_med_skinfo, /* RTP sock info */ &local_sdp); /* the SDP result */ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create the INVITE session, and pass the SDP returned earlier * as the session's initial capability. */ status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create initial INVITE request. * This INVITE request will contain a perfectly good request and * an SDP body as well. */ status = pjsip_inv_invite(g_inv, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Send initial INVITE request. * From now on, the invite session's state will be reported to us * via the invite session callbacks. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } else { /* No URL to make call to */ PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls...")); } /* Loop until one call is completed */ for (;!g_complete;) { pj_time_val timeout = {0, 10}; pjsip_endpt_handle_events(g_endpt, &timeout); } /* On exit, dump current memory usage: */ dump_pool_usage(THIS_FILE, &cp); return 0;}/* * Callback when INVITE session state has changed. * This callback is registered when the invite session module is initialized. * We mostly want to know when the invite session has been disconnected, * so that we can quit the application. */static void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){ PJ_UNUSED_ARG(e); if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { PJ_LOG(3,(THIS_FILE, "Call DISCONNECTED [reason=%d (%s)]", inv->cause, pjsip_get_status_text(inv->cause)->ptr)); PJ_LOG(3,(THIS_FILE, "One call completed, application quitting...")); g_complete = 1; } else { PJ_LOG(3,(THIS_FILE, "Call state changed to %s", pjsip_inv_state_name(inv->state))); }}/* This callback is called when dialog has forked. */static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e){ /* To be done... */ PJ_UNUSED_ARG(inv); PJ_UNUSED_ARG(e);}/* * Callback when incoming requests outside any transactions and any * dialogs are received. We're only interested to hande incoming INVITE * request, and we'll reject any other requests with 500 response. */static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){ pjsip_dialog *dlg; pjmedia_sdp_session *local_sdp; pjsip_tx_data *tdata; unsigned options = 0; pj_status_t status; /* * Respond (statelessly) any non-INVITE requests with 500 */ if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) { pj_str_t reason = pj_str("Simple UA unable to handle " "this request"); pjsip_endpt_respond_stateless( g_endpt, rdata, 500, &reason, NULL, NULL); } return PJ_TRUE; } /* * Reject INVITE if we already have an INVITE session in progress. */ if (g_inv) { pj_str_t reason = pj_str("Another call is in progress"); pjsip_endpt_respond_stateless( g_endpt, rdata, 500, &reason, NULL, NULL); return PJ_TRUE; } /* Verify that we can handle the request. */ status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, g_endpt, NULL); if (status != PJ_SUCCESS) { pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE"); pjsip_endpt_respond_stateless( g_endpt, rdata, 500, &reason, NULL, NULL); return PJ_TRUE; } /* * Create UAS dialog. */ status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, NULL, /* contact */ &dlg); if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } /* * Get media capability from media endpoint: */ status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1, &g_med_skinfo, &local_sdp); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Create invite session, and pass both the UAS dialog and the SDP * capability to the session. */ status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Initially send 180 response. * * The very first response to an INVITE must be created with * pjsip_inv_initial_answer(). Subsequent responses to the same * transaction MUST use pjsip_inv_answer(). */ status = pjsip_inv_initial_answer(g_inv, rdata, 180, NULL, NULL, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* Send the 180 response. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Now create 200 response. */ status = pjsip_inv_answer( g_inv, 200, NULL, /* st_code and st_text */ NULL, /* SDP already specified */ &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Send the 200 response. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* Done. * When the call is disconnected, it will be reported via the callback. */ return PJ_TRUE;} /* * Callback when SDP negotiation has completed. * We are interested with this callback because we want to start media * as soon as SDP negotiation is completed. */static void call_on_media_update( pjsip_inv_session *inv, pj_status_t status){ pjmedia_session_info sess_info; const pjmedia_sdp_session *local_sdp; const pjmedia_sdp_session *remote_sdp; pjmedia_port *media_port; if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "SDP negotiation has failed", status); /* Here we should disconnect call if we're not in the middle * of initializing an UAS dialog and if this is not a re-INVITE. */ return; } /* Get local and remote SDP. * We need both SDPs to create a media session. */ status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); /* Create session info based on the two SDPs. * We only support one stream per session for now. */ status = pjmedia_session_info_from_sdp(inv->dlg->pool, g_med_endpt, 1, &sess_info, local_sdp, remote_sdp); if (status != PJ_SUCCESS) { app_perror( THIS_FILE, "Unable to create media session", status); return; } /* If required, we can also change some settings in the session info, * (such as jitter buffer settings, codec settings, etc) before we * create the session. */ /* Create new media session, passing the two SDPs, and also the * media socket that we created earlier. * The media session is active immediately. */ status = pjmedia_session_create( g_med_endpt, &sess_info, &g_med_transport, NULL, &g_med_session ); if (status != PJ_SUCCESS) { app_perror( THIS_FILE, "Unable to create media session", status); return; } /* Get the media port interface of the first stream in the session. * Media port interface is basicly a struct containing get_frame() and * put_frame() function. With this media port interface, we can attach * the port interface to conference bridge, or directly to a sound * player/recorder device. */ pjmedia_session_get_port(g_med_session, 0, &media_port); /* Create a sound Player device and connect the media port to the * sound device. */ status = pjmedia_snd_port_create_player( inv->pool, /* pool */ -1, /* sound dev id */ media_port->info.clock_rate, /* clock rate */ media_port->info.channel_count, /* channel count */ media_port->info.samples_per_frame, /* samples per frame*/ media_port->info.bits_per_sample, /* bits per sample */ 0, /* options */ &g_snd_player); if (status != PJ_SUCCESS) { app_perror( THIS_FILE, "Unable to create sound player", status); PJ_LOG(3,(THIS_FILE, "%d %d %d %d", media_port->info.clock_rate, /* clock rate */ media_port->info.channel_count, /* channel count */ media_port->info.samples_per_frame, /* samples per frame*/ media_port->info.bits_per_sample /* bits per sample */ )); return; } status = pjmedia_snd_port_connect(g_snd_player, media_port); /* Create a sound recorder device and connect the media port to the * sound device. */ status = pjmedia_snd_port_create_rec( inv->pool, /* pool */ -1, /* sound dev id */ media_port->info.clock_rate, /* clock rate */ media_port->info.channel_count, /* channel count */ media_port->info.samples_per_frame, /* samples per frame*/ media_port->info.bits_per_sample, /* bits per sample */ 0, /* options */ &g_snd_rec); if (status != PJ_SUCCESS) { app_perror( THIS_FILE, "Unable to create sound recorder", status); return; } status = pjmedia_snd_port_connect(g_snd_rec, media_port); /* Done with media. */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -