📄 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 + -