From 4c1830ca1329c2d2d8d33a0210dd0458ed05773d Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Sat, 14 Jun 2008 19:42:37 +0000 Subject: Added ringback/alert tones in pjsua git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2021 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip-apps/src/pjsua/pjsua_app.c | 198 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 1 deletion(-) (limited to 'pjsip-apps') diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 17508bc9..0cb0ad1d 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -24,10 +24,25 @@ //#define STEREO_DEMO +/* Ringtones */ +#define RINGBACK_FREQ1 440 +#define RINGBACK_FREQ2 480 +#define RINGBACK_ON 2000 +#define RINGBACK_OFF 4000 + +#define RING_FREQ1 500 +#define RING_FREQ2 660 +#define RING_ON 100 +#define RING_OFF 100 +#define RING_INTERVAL 4000 + + /* Call specific data */ struct call_data { pj_timer_entry timer; + pj_bool_t ringback_on; + pj_bool_t ring_on; }; @@ -86,6 +101,15 @@ static struct app_config int capture_dev, playback_dev; unsigned capture_lat, playback_lat; + + pj_bool_t no_tones; + int ringback_slot; + int ringback_cnt; + pjmedia_port *ringback_port; + int ring_slot; + int ring_cnt; + pjmedia_port *ring_port; + } app_config; @@ -105,6 +129,11 @@ static void stereo_demo(); #endif pj_status_t app_destroy(void); +static void ringback_start(pjsua_call_id call_id); +static void ring_start(pjsua_call_id call_id); +static void ring_stop(pjsua_call_id call_id); + + /***************************************************************************** * Configuration manipulation */ @@ -204,6 +233,7 @@ static void usage(void) puts (" --snd-auto-close=N Auto close audio device when it is idle for N seconds."); puts (" Specify N=-1 (default) to disable this feature."); puts (" Specify N=0 for instant close when unused."); + puts (" --no-tones Disable audible tones"); puts (""); puts ("Media Transport Options:"); @@ -264,6 +294,8 @@ static void default_config(struct app_config *cfg) cfg->playback_dev = PJSUA_INVALID_ID; cfg->capture_lat = PJMEDIA_SND_DEFAULT_REC_LATENCY; cfg->playback_lat = PJMEDIA_SND_DEFAULT_PLAY_LATENCY; + cfg->ringback_slot = PJSUA_INVALID_ID; + cfg->ring_slot = PJSUA_INVALID_ID; for (i=0; iacc_cfg); ++i) pjsua_acc_config_default(&cfg->acc_cfg[i]); @@ -425,7 +457,7 @@ static pj_status_t parse_args(int argc, char *argv[], OPT_TLS_PASSWORD, OPT_TLS_VERIFY_SERVER, OPT_TLS_VERIFY_CLIENT, OPT_TLS_NEG_TIMEOUT, OPT_CAPTURE_DEV, OPT_PLAYBACK_DEV, - OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, + OPT_CAPTURE_LAT, OPT_PLAYBACK_LAT, OPT_NO_TONES, OPT_STDOUT_REFRESH, OPT_STDOUT_REFRESH_TEXT, OPT_AUTO_UPDATE_NAT,OPT_USE_COMPACT_FORM,OPT_DIS_CODEC }; @@ -518,6 +550,7 @@ static pj_status_t parse_args(int argc, char *argv[], { "stdout-refresh", 1, 0, OPT_STDOUT_REFRESH}, { "stdout-refresh-text", 1, 0, OPT_STDOUT_REFRESH_TEXT}, { "snd-auto-close", 1, 0, OPT_SND_AUTO_CLOSE}, + { "no-tones", 0, 0, OPT_NO_TONES}, { NULL, 0, 0, 0} }; pj_status_t status; @@ -1116,6 +1149,10 @@ static pj_status_t parse_args(int argc, char *argv[], cfg->media_cfg.snd_auto_close_time = atoi(pj_optarg); break; + case OPT_NO_TONES: + cfg->no_tones = PJ_TRUE; + break; + default: PJ_LOG(1,(THIS_FILE, "Argument \"%s\" is not valid. Use --help to see help", @@ -1517,6 +1554,9 @@ static int write_settings(const struct app_config *config, config->media_cfg.snd_auto_close_time); pj_strcat2(&cfg, line); } + if (config->no_tones) { + pj_strcat2(&cfg, "--no-tones\n"); + } /* Sound device latency */ if (config->capture_lat != PJMEDIA_SND_DEFAULT_REC_LATENCY) { @@ -1693,6 +1733,95 @@ static void app_dump(pj_bool_t detail) * Console application */ +static void ringback_start(pjsua_call_id call_id) +{ + if (app_config.no_tones) + return; + + if (app_config.call_data[call_id].ringback_on) + return; + + app_config.call_data[call_id].ringback_on = PJ_TRUE; + + if (++app_config.ringback_cnt==1 && + app_config.ringback_slot!=PJSUA_INVALID_ID) + { + pjmedia_tone_desc tone; + + pj_bzero(&tone, sizeof(tone)); + tone.freq1 = RINGBACK_FREQ1; + tone.freq2 = RINGBACK_FREQ2; + tone.on_msec = RINGBACK_ON; + tone.off_msec = RINGBACK_OFF; + pjmedia_tonegen_play(app_config.ringback_port, 1, &tone, + PJMEDIA_TONEGEN_LOOP); + + pjsua_conf_connect(app_config.ringback_slot, 0); + } +} + +static void ring_stop(pjsua_call_id call_id) +{ + if (app_config.no_tones) + return; + + if (app_config.call_data[call_id].ringback_on) { + app_config.call_data[call_id].ringback_on = PJ_FALSE; + + pj_assert(app_config.ringback_cnt>0); + if (--app_config.ringback_cnt == 0 && + app_config.ringback_slot!=PJSUA_INVALID_ID) + { + pjsua_conf_disconnect(app_config.ringback_slot, 0); + pjmedia_tonegen_stop(app_config.ringback_port); + } + } + + if (app_config.call_data[call_id].ring_on) { + app_config.call_data[call_id].ring_on = PJ_FALSE; + + pj_assert(app_config.ring_cnt>0); + if (--app_config.ring_cnt == 0 && + app_config.ring_slot!=PJSUA_INVALID_ID) + { + pjsua_conf_disconnect(app_config.ring_slot, 0); + pjmedia_tonegen_stop(app_config.ring_port); + } + } +} + +static void ring_start(pjsua_call_id call_id) +{ + if (app_config.no_tones) + return; + + if (app_config.call_data[call_id].ring_on) + return; + + app_config.call_data[call_id].ring_on = PJ_TRUE; + + if (++app_config.ring_cnt==1 && + app_config.ring_slot!=PJSUA_INVALID_ID) + { + unsigned i; + pjmedia_tone_desc tone[3]; + + pj_bzero(&tone, sizeof(tone)); + for (i=0; iline.status.code; reason = msg->line.status.reason; + /* Start ringback for 180 for UAC unless there's SDP in 180 */ + if (call_info.role==PJSIP_ROLE_UAC && code==180 && + msg->body == NULL && + call_info.media_status==PJSUA_CALL_MEDIA_NONE) + { + ringback_start(call_id); + } + PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s (%d %.*s)", call_id, call_info.state_text.ptr, code, (int)reason.slen, reason.ptr)); @@ -1883,6 +2023,9 @@ static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsua_call_get_info(call_id, &call_info); + /* Start ringback */ + ring_start(call_id); + if (app_config.auto_answer > 0) { pjsua_call_answer(call_id, app_config.auto_answer, NULL, NULL); } @@ -1977,6 +2120,9 @@ static void on_call_media_state(pjsua_call_id call_id) pjsua_call_get_info(call_id, &call_info); + /* Stop ringback */ + ring_stop(call_id); + if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) { pj_bool_t connect_sound = PJ_TRUE; @@ -3687,6 +3833,38 @@ pj_status_t app_init(int argc, char *argv[]) pj_memcpy(&tcp_cfg, &app_config.udp_cfg, sizeof(tcp_cfg)); + /* Create ringback tones */ + if (app_config.no_tones == PJ_FALSE) { + pj_str_t name; + + /* Ringback tone (call is ringing) */ + name = pj_str("ringback"); + status = pjmedia_tonegen_create2(app_config.pool, &name, 8000, 1, 160, + 16, PJMEDIA_TONEGEN_LOOP, + &app_config.ringback_port); + if (status != PJ_SUCCESS) + goto on_error; + + status = pjsua_conf_add_port(app_config.pool, app_config.ringback_port, + &app_config.ringback_slot); + if (status != PJ_SUCCESS) + goto on_error; + + /* Ring (to alert incoming call) */ + name = pj_str("ring"); + status = pjmedia_tonegen_create2(app_config.pool, &name, 8000, 1, 160, + 16, PJMEDIA_TONEGEN_LOOP, + &app_config.ring_port); + if (status != PJ_SUCCESS) + goto on_error; + + status = pjsua_conf_add_port(app_config.pool, app_config.ring_port, + &app_config.ring_slot); + if (status != PJ_SUCCESS) + goto on_error; + + } + /* Add UDP transport unless it's disabled. */ if (!app_config.no_udp) { pjsua_acc_id aid; @@ -3876,6 +4054,24 @@ pj_status_t app_destroy(void) } #endif + /* Close ringback port */ + if (app_config.ringback_port && + app_config.ringback_slot != PJSUA_INVALID_ID) + { + pjsua_conf_remove_port(app_config.ringback_slot); + app_config.ringback_slot = PJSUA_INVALID_ID; + pjmedia_port_destroy(app_config.ringback_port); + app_config.ringback_port = NULL; + } + + /* Close ring port */ + if (app_config.ring_port && app_config.ring_slot != PJSUA_INVALID_ID) { + pjsua_conf_remove_port(app_config.ring_slot); + app_config.ring_slot = PJSUA_INVALID_ID; + pjmedia_port_destroy(app_config.ring_port); + app_config.ring_port = NULL; + } + /* Close tone generators */ for (i=0; i