From e3399b0820e6010b0a2d423261d54111af63e528 Mon Sep 17 00:00:00 2001 From: Nanang Izzuddin Date: Fri, 13 Jun 2008 17:01:46 +0000 Subject: Ticket #540: Added pjsua-lib feature auto-close sound device on idle and new pjsua option --snd-auto-close=N git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@2018 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip-apps/src/pjsua/pjsua_app.c | 24 ++++-- pjsip-apps/src/symbian_ua/ua.cpp | 1 + pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp | 1 + pjsip/include/pjsua-lib/pjsua.h | 8 ++ pjsip/include/pjsua-lib/pjsua_internal.h | 2 + pjsip/src/pjsua-lib/pjsua_core.c | 1 + pjsip/src/pjsua-lib/pjsua_media.c | 102 +++++++++++++++++++---- 7 files changed, 118 insertions(+), 21 deletions(-) diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index d80e16c0..17508bc9 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -201,6 +201,9 @@ static void usage(void) puts (" --playback-dev=id Audio playback device ID (default=-1)"); puts (" --capture-lat=N Audio capture latency, in ms (default=10)"); puts (" --playback-lat=N Audio playback latency, in ms (default=100)"); + 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 (""); puts ("Media Transport Options:"); @@ -400,7 +403,7 @@ static pj_status_t parse_args(int argc, char *argv[], int c; int option_index; enum { OPT_CONFIG_FILE=127, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, - OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, + OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO, OPT_SND_AUTO_CLOSE, OPT_LOCAL_PORT, OPT_IP_ADDR, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR, OPT_REG_TIMEOUT, OPT_PUBLISH, OPT_ID, OPT_CONTACT, OPT_100REL, OPT_USE_IMS, OPT_REALM, OPT_USERNAME, OPT_PASSWORD, @@ -514,6 +517,7 @@ static pj_status_t parse_args(int argc, char *argv[], { "playback-lat", 1, 0, OPT_PLAYBACK_LAT}, { "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}, { NULL, 0, 0, 0} }; pj_status_t status; @@ -1108,6 +1112,10 @@ static pj_status_t parse_args(int argc, char *argv[], cfg->playback_lat = atoi(pj_optarg); break; + case OPT_SND_AUTO_CLOSE: + cfg->media_cfg.snd_auto_close_time = atoi(pj_optarg); + break; + default: PJ_LOG(1,(THIS_FILE, "Argument \"%s\" is not valid. Use --help to see help", @@ -1504,6 +1512,11 @@ static int write_settings(const struct app_config *config, pj_ansi_sprintf(line, "--playback-dev %d\n", config->playback_dev); pj_strcat2(&cfg, line); } + if (config->media_cfg.snd_auto_close_time != -1) { + pj_ansi_sprintf(line, "--snd-auto-close %d\n", + config->media_cfg.snd_auto_close_time); + pj_strcat2(&cfg, line); + } /* Sound device latency */ if (config->capture_lat != PJMEDIA_SND_DEFAULT_REC_LATENCY) { @@ -3786,10 +3799,11 @@ pj_status_t app_init(int argc, char *argv[]) } #endif - if (app_config.capture_dev != PJSUA_INVALID_ID - || app_config.playback_dev != PJSUA_INVALID_ID) { - status - = pjsua_set_snd_dev(app_config.capture_dev, app_config.playback_dev); + if (app_config.capture_dev != PJSUA_INVALID_ID || + app_config.playback_dev != PJSUA_INVALID_ID) + { + status = pjsua_set_snd_dev(app_config.capture_dev, + app_config.playback_dev); if (status != PJ_SUCCESS) goto on_error; } diff --git a/pjsip-apps/src/symbian_ua/ua.cpp b/pjsip-apps/src/symbian_ua/ua.cpp index 34935a18..5396bc72 100644 --- a/pjsip-apps/src/symbian_ua/ua.cpp +++ b/pjsip-apps/src/symbian_ua/ua.cpp @@ -334,6 +334,7 @@ static pj_status_t app_startup() med_cfg.audio_frame_ptime = 40; med_cfg.ec_tail_len = 0; med_cfg.enable_ice = USE_ICE; + med_cfg.snd_auto_close_time = 5; // wait for 5 seconds idle before sound dev get auto-closed status = pjsua_init(&cfg, &log_cfg, &med_cfg); if (status != PJ_SUCCESS) { diff --git a/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp b/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp index bd9864b1..7d693b41 100644 --- a/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp +++ b/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp @@ -326,6 +326,7 @@ int symbian_ua_init() med_cfg.audio_frame_ptime = 40; med_cfg.ec_tail_len = 0; med_cfg.enable_ice = USE_ICE; + med_cfg.snd_auto_close_time = 5; // wait for 5 seconds idle before sound dev get auto-closed pjsua_logging_config log_cfg; diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 21d8ffb1..0ee97f9c 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -3908,6 +3908,14 @@ struct pjsua_media_config * Specify the credential to authenticate with the TURN server. */ pj_stun_auth_cred turn_auth_cred; + + /** + * Specify idle time of sound device before it is automatically closed, + * in seconds. + * + * Default : -1 (Disable the auto-close feature of sound device) + */ + int snd_auto_close_time; }; diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index dfb9f84a..766d8782 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -236,7 +236,9 @@ struct pjsua_data int cap_dev; /**< Capture device ID. */ int play_dev; /**< Playback device ID. */ pj_bool_t no_snd; /**< No sound (app will manage it) */ + pj_pool_t *snd_pool; /**< Sound's private pool. */ pjmedia_snd_port *snd_port; /**< Sound port. */ + pj_timer_entry snd_idle_timer;/**< Sound device idle timer. */ pjmedia_master_port *null_snd; /**< Master port for null sound. */ pjmedia_port *null_port; /**< Null port. */ diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index a50ff433..a59e9346 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -171,6 +171,7 @@ PJ_DEF(void) pjsua_media_config_default(pjsua_media_config *cfg) cfg->ilbc_mode = PJSUA_DEFAULT_ILBC_MODE; cfg->ec_tail_len = PJSUA_DEFAULT_EC_TAIL_LEN; cfg->jb_init = cfg->jb_min_pre = cfg->jb_max_pre = cfg->jb_max = -1; + cfg->snd_auto_close_time = -1; cfg->turn_conn_type = PJ_TURN_TP_UDP; } diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index d8c2cd9c..0f923452 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -22,7 +22,9 @@ #define THIS_FILE "pjsua_media.c" -#define DEFAULT_RTP_PORT 4000 +#define DEFAULT_RTP_PORT 4000 + +#define NULL_SND_DEV_ID -99 #ifndef PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT # define PJSUA_REQUIRE_CONSECUTIVE_RTCP_PORT 0 @@ -423,6 +425,20 @@ on_error: return status; } +/* Timer callback to close sound device */ +static void close_snd_timer_cb( pj_timer_heap_t *th, + pj_timer_entry *entry) +{ + PJ_UNUSED_ARG(th); + + PJ_LOG(4,(THIS_FILE,"Closing sound device after idle for %d seconds", + pjsua_var.media_cfg.snd_auto_close_time)); + + entry->id = PJ_FALSE; + + close_snd_dev(); +} + /* * Start pjsua media subsystem. @@ -444,16 +460,8 @@ pj_status_t pjsua_media_subsys_start(void) return status; } - /* Create sound port if none is created yet */ - if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && - !pjsua_var.no_snd) - { - status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); - if (status != PJ_SUCCESS) { - pjsua_perror(THIS_FILE, "Error opening sound device", status); - return status; - } - } + pj_timer_entry_init(&pjsua_var.snd_idle_timer, PJ_FALSE, NULL, + &close_snd_timer_cb); return PJ_SUCCESS; } @@ -1327,6 +1335,25 @@ PJ_DEF(pj_status_t) pjsua_conf_remove_port(pjsua_conf_port_id id) PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source, pjsua_conf_port_id sink) { + /* If sound device idle timer is active, cancel it first. */ + if (pjsua_var.snd_idle_timer.id) { + pjsip_endpt_cancel_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer); + pjsua_var.snd_idle_timer.id = PJ_FALSE; + } + + /* Create sound port if none is instantiated */ + if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && + !pjsua_var.no_snd) + { + pj_status_t status; + + status = pjsua_set_snd_dev(pjsua_var.cap_dev, pjsua_var.play_dev); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Error opening sound device", status); + return status; + } + } + return pjmedia_conf_connect_port(pjsua_var.mconf, source, sink, 0); } @@ -1337,7 +1364,31 @@ PJ_DEF(pj_status_t) pjsua_conf_connect( pjsua_conf_port_id source, PJ_DEF(pj_status_t) pjsua_conf_disconnect( pjsua_conf_port_id source, pjsua_conf_port_id sink) { - return pjmedia_conf_disconnect_port(pjsua_var.mconf, source, sink); + pj_status_t status; + + status = pjmedia_conf_disconnect_port(pjsua_var.mconf, source, sink); + if (status != PJ_SUCCESS) + return status; + + /* If no port is connected, sound device must be idle. Activate sound + * device auto-close timer. + */ + if ((pjsua_var.snd_port!=NULL || pjsua_var.null_snd!=NULL) && + pjsua_var.snd_idle_timer.id==PJ_FALSE && + pjmedia_conf_get_connect_count(pjsua_var.mconf) == 0 && + pjsua_var.media_cfg.snd_auto_close_time >= 0) + { + pj_time_val delay; + + delay.msec = 0; + delay.sec = pjsua_var.media_cfg.snd_auto_close_time; + + pjsua_var.snd_idle_timer.id = PJ_TRUE; + pjsip_endpt_schedule_timer(pjsua_var.endpt, &pjsua_var.snd_idle_timer, + &delay); + } + + return status; } @@ -1843,6 +1894,10 @@ static void close_snd_dev(void) pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE); pjsua_var.null_snd = NULL; } + + if (pjsua_var.snd_pool) + pj_pool_release(pjsua_var.snd_pool); + pjsua_var.snd_pool = NULL; } /* @@ -1863,9 +1918,17 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, pj_str_t tmp; pj_status_t status = -1; + /* Check if NULL sound device is used */ + if (NULL_SND_DEV_ID == capture_dev || NULL_SND_DEV_ID == playback_dev) { + return pjsua_set_null_snd_dev(); + } + /* Close existing sound port */ close_snd_dev(); + /* Create memory pool for sound device. */ + pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000); + PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM); /* Set default clock rate */ clock_rates[0] = pjsua_var.media_cfg.snd_clock_rate; @@ -1887,7 +1950,7 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, /* Create the sound device. Sound port will start immediately. */ fps = 1000 / pjsua_var.media_cfg.audio_frame_ptime; - status = pjmedia_snd_port_create(pjsua_var.pool, capture_dev, + status = pjmedia_snd_port_create(pjsua_var.snd_pool, capture_dev, playback_dev, clock_rates[i], pjsua_var.media_cfg.channel_count, @@ -1914,7 +1977,7 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, resample_opt |= PJMEDIA_RESAMPLE_USE_LINEAR; } - status = pjmedia_resample_port_create(pjsua_var.pool, + status = pjmedia_resample_port_create(pjsua_var.snd_pool, conf_port, selected_clock_rate, resample_opt, @@ -1948,7 +2011,7 @@ PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev, } /* Set AEC */ - pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.pool, + pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.snd_pool, pjsua_var.media_cfg.ec_tail_len, pjsua_var.media_cfg.ec_options); @@ -2019,6 +2082,10 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void) /* Close existing sound device */ close_snd_dev(); + /* Create memory pool for sound device. */ + pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000); + PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM); + PJ_LOG(4,(THIS_FILE, "Opening null sound device..")); /* Get the port0 of the conference bridge. */ @@ -2028,7 +2095,7 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void) /* Create master port, connecting port0 of the conference bridge to * a null port. */ - status = pjmedia_master_port_create(pjsua_var.pool, pjsua_var.null_port, + status = pjmedia_master_port_create(pjsua_var.snd_pool, pjsua_var.null_port, conf_port, 0, &pjsua_var.null_snd); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create null sound device", @@ -2040,6 +2107,9 @@ PJ_DEF(pj_status_t) pjsua_set_null_snd_dev(void) status = pjmedia_master_port_start(pjsua_var.null_snd); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + pjsua_var.cap_dev = NULL_SND_DEV_ID; + pjsua_var.play_dev = NULL_SND_DEV_ID; + return PJ_SUCCESS; } -- cgit v1.2.3