Index: /pjproject/trunk/pjsip-apps/src/swig/symbols.i
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5272)
+++ /pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5273)
@@ -166,2 +166,4 @@
 typedef enum pjsua_create_media_transport_flag {PJSUA_MED_TP_CLOSE_MEMBER = 1} pjsua_create_media_transport_flag;
 
+typedef enum pjsua_snd_dev_mode {PJSUA_SND_DEV_SPEAKER_ONLY = 1, PJSUA_SND_DEV_NO_IMMEDIATE_OPEN = 2} pjsua_snd_dev_mode;
+
Index: /pjproject/trunk/pjsip-apps/src/swig/symbols.lst
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5272)
+++ /pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5273)
@@ -34,3 +34,3 @@
 pjsip-ua/sip_inv.h              pjsip_inv_state
 
-pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag
+pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5272)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5273)
@@ -5998,4 +5998,60 @@
 } pjsua_media_transport;
 
+/**
+ * This enumeration specifies the sound device mode.
+ */
+typedef enum pjsua_snd_dev_mode
+{
+    /**
+     * Open sound device without mic (speaker only).
+     */
+    PJSUA_SND_DEV_SPEAKER_ONLY = 1,
+
+    /**
+     * Do not open sound device, after setting the sound device.
+     */
+    PJSUA_SND_DEV_NO_IMMEDIATE_OPEN  = 2
+
+} pjsua_snd_dev_mode;
+
+
+/**
+ * This structure specifies the parameters to set the sound device.
+ * Use pjsua_snd_dev_param_default() to initialize this structure with
+ * default values.
+ */
+typedef struct pjsua_snd_dev_param
+{
+    /*
+     * Capture dev id.
+     *
+     * Default: PJMEDIA_AUD_DEFAULT_CAPTURE_DEV
+     */
+    int			capture_dev;
+
+    /*
+     * Playback dev id.
+     *
+     * Default: PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV
+     */
+    int			playback_dev;
+
+    /*
+     * Sound device mode, refer to #pjsua_snd_dev_mode.
+     *
+     * Default: 0
+     */
+    unsigned		mode;
+
+} pjsua_snd_dev_param;
+
+
+/**
+ * Initialize pjsua_snd_dev_param with default values.
+ *
+ * @param prm		The parameter.
+ */
+PJ_DECL(void) pjsua_snd_dev_param_default(pjsua_snd_dev_param *prm);
+
 
 /**
@@ -6385,4 +6441,13 @@
 				       int playback_dev);
 
+/**
+ * Select or change sound device according to the specified param.
+ *
+ * @param snd_param	Sound device param. 
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_set_snd_dev2(pjsua_snd_dev_param *snd_param);
+
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5272)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5273)
@@ -479,4 +479,5 @@
     pjmedia_port	*null_port; /**< Null port.			*/
     pj_bool_t		 snd_is_on; /**< Media flow is currently active */
+    unsigned		 snd_mode;  /**< Sound device mode.		*/
 
     /* Video device */
Index: /pjproject/trunk/pjsip/include/pjsua2/media.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/media.hpp	(revision 5272)
+++ /pjproject/trunk/pjsip/include/pjsua2/media.hpp	(revision 5273)
@@ -768,5 +768,7 @@
     /**
      * Select or change capture sound device. Application may call this
-     * function at any time to replace current sound device.
+     * function at any time to replace current sound device. Calling this 
+     * method will not change the state of the sound device (opened/closed).
+     * Note that this method will override the mode set by setSndDevMode().
      *
      * @param capture_dev   	Device ID of the capture device.
@@ -776,5 +778,7 @@
     /**
      * Select or change playback sound device. Application may call this
-     * function at any time to replace current sound device.
+     * function at any time to replace current sound device. Calling this 
+     * method will not change the state of the sound device (opened/closed).
+     * Note that this method will override the mode set by setSndDevMode().
      *
      * @param playback_dev   	Device ID of the playback device.
@@ -806,4 +810,13 @@
      */
     MediaPort *setNoDev();
+
+    /**
+     * Set sound device mode.
+     * 
+     * @param mode		The sound device mode, as bitmask combination 
+     *				of #pjsua_snd_dev_mode
+     *
+     */
+    void setSndDevMode(unsigned mode) const throw(Error);
 
     /**
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c	(revision 5272)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c	(revision 5273)
@@ -688,4 +688,10 @@
 }
 
+PJ_DEF(void) pjsua_snd_dev_param_default(pjsua_snd_dev_param *prm)
+{
+    pj_bzero(prm, sizeof(*prm));
+    prm->capture_dev = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
+    prm->playback_dev = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
+}
 
 /*
@@ -1697,4 +1703,5 @@
     pjmedia_port *conf_port;
     pj_status_t status;
+    pj_bool_t speaker_only = (pjsua_var.snd_mode & PJSUA_SND_DEV_SPEAKER_ONLY);
 
     PJ_ASSERT_RETURN(param, PJ_EINVAL);
@@ -1725,5 +1732,6 @@
 	param->on_rec_frame = &on_aud_prev_rec_frame;
 
-    PJ_LOG(4,(THIS_FILE, "Opening sound device %s@%d/%d/%dms",
+    PJ_LOG(4,(THIS_FILE, "Opening sound device (%s) %s@%d/%d/%dms",
+	      speaker_only?"speaker only":"speaker + mic",
 	      get_fmt_name(param->base.ext_fmt.id),
 	      param->base.clock_rate, param->base.channel_count,
@@ -1732,6 +1740,19 @@
     pj_log_push_indent();
 
-    status = pjmedia_snd_port_create2( pjsua_var.snd_pool,
-				       param, &pjsua_var.snd_port);
+    if (speaker_only) {
+	status = pjmedia_snd_port_create_player(pjsua_var.snd_pool,
+						-1,
+						param->base.clock_rate,
+						param->base.channel_count,
+						param->base.samples_per_frame,
+						param->base.bits_per_sample, 
+						0,
+						&pjsua_var.snd_port);
+
+    } else {
+	status = pjmedia_snd_port_create2(pjsua_var.snd_pool,
+					  param, &pjsua_var.snd_port);
+    }
+
     if (status != PJ_SUCCESS)
 	goto on_error;
@@ -1921,10 +1942,24 @@
 
 
+PJ_DEF(pj_status_t) pjsua_set_snd_dev(int capture_dev,
+				      int playback_dev)
+{
+    pjsua_snd_dev_param param;
+
+    pjsua_snd_dev_param_default(&param);
+
+    param.capture_dev = capture_dev;
+    param.playback_dev = playback_dev;
+    /* Always open the sound device. */
+    param.mode = 0;
+
+    return pjsua_set_snd_dev2(&param);
+}
+
 /*
  * Select or change sound device. Application may call this function at
  * any time to replace current sound device.
  */
-PJ_DEF(pj_status_t) pjsua_set_snd_dev( int capture_dev,
-				       int playback_dev)
+PJ_DEF(pj_status_t) pjsua_set_snd_dev2(pjsua_snd_dev_param *snd_param)
 {
     unsigned alt_cr_cnt = 1;
@@ -1932,14 +1967,19 @@
     unsigned i;
     pj_status_t status = -1;
+    unsigned orig_snd_dev_mode = pjsua_var.snd_mode;
+    pj_bool_t no_change = (pjsua_var.snd_is_on || (!pjsua_var.snd_is_on &&
+			   (snd_param->mode & 
+			    PJSUA_SND_DEV_NO_IMMEDIATE_OPEN)));
 
     PJ_LOG(4,(THIS_FILE, "Set sound device: capture=%d, playback=%d",
-	      capture_dev, playback_dev));
+	      snd_param->capture_dev, snd_param->playback_dev));
     pj_log_push_indent();
 
     PJSUA_LOCK();
 
-    if (pjsua_var.cap_dev == capture_dev &&
-	pjsua_var.play_dev == playback_dev &&
-	pjsua_var.snd_is_on && !pjsua_var.no_snd)
+    if (pjsua_var.cap_dev == snd_param->capture_dev &&
+	pjsua_var.play_dev == snd_param->playback_dev &&
+	pjsua_var.snd_mode == snd_param->mode &&
+	!pjsua_var.no_snd && no_change)
     {
 	PJ_LOG(4, (THIS_FILE, "No changes in capture and playback devices"));
@@ -1950,9 +1990,24 @@
     
     /* Null-sound */
-    if (capture_dev==NULL_SND_DEV_ID && playback_dev==NULL_SND_DEV_ID) {
+    if (snd_param->capture_dev == NULL_SND_DEV_ID && 
+	snd_param->playback_dev == NULL_SND_DEV_ID) 
+    {
 	PJSUA_UNLOCK();
 	status = pjsua_set_null_snd_dev();
 	pj_log_pop_indent();
 	return status;
+    }
+
+    pjsua_var.snd_mode = snd_param->mode;
+
+    if (!pjsua_var.no_snd &&
+	(snd_param->mode & PJSUA_SND_DEV_NO_IMMEDIATE_OPEN))
+    {
+	pjsua_var.cap_dev = snd_param->capture_dev;
+	pjsua_var.play_dev = snd_param->playback_dev;
+
+	PJSUA_UNLOCK();	
+	pj_log_pop_indent();
+	return PJ_SUCCESS;
     }
 
@@ -1983,5 +2038,6 @@
 	pjmedia_snd_port_param_default(&param);
 	param.ec_options = pjsua_var.media_cfg.ec_options;
-	status = create_aud_param(&param.base, capture_dev, playback_dev,
+	status = create_aud_param(&param.base, snd_param->capture_dev, 
+				  snd_param->playback_dev, 
 				  alt_cr[i], pjsua_var.media_cfg.channel_count,
 				  samples_per_frame, 16);
@@ -2009,4 +2065,5 @@
 
 on_error:
+    pjsua_var.snd_mode = orig_snd_dev_mode;
     PJSUA_UNLOCK();
     pj_log_pop_indent();
Index: /pjproject/trunk/pjsip/src/pjsua2/media.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/media.cpp	(revision 5272)
+++ /pjproject/trunk/pjsip/src/pjsua2/media.cpp	(revision 5273)
@@ -680,15 +680,27 @@
 
 void AudDevManager::setCaptureDev(int capture_dev) const throw(Error)
-{
-    int playback_dev = getPlaybackDev();
-
-    PJSUA2_CHECK_EXPR( pjsua_set_snd_dev(capture_dev, playback_dev) );
+{    
+    pjsua_snd_dev_param param;
+    pjsua_snd_dev_param_default(&param);    
+
+    param.capture_dev = capture_dev;
+    param.playback_dev = getPlaybackDev();    
+
+    param.mode = PJSUA_SND_DEV_NO_IMMEDIATE_OPEN;    
+
+    PJSUA2_CHECK_EXPR( pjsua_set_snd_dev2(&param) );
 }
 
 void AudDevManager::setPlaybackDev(int playback_dev) const throw(Error)
 {
-    int capture_dev = getCaptureDev();
-
-    PJSUA2_CHECK_EXPR( pjsua_set_snd_dev(capture_dev, playback_dev) );
+    pjsua_snd_dev_param param;
+    pjsua_snd_dev_param_default(&param);    
+
+    param.capture_dev = getCaptureDev();
+    param.playback_dev = playback_dev;
+
+    param.mode = PJSUA_SND_DEV_NO_IMMEDIATE_OPEN;    
+
+    PJSUA2_CHECK_EXPR( pjsua_set_snd_dev2(&param) );    
 }
 
@@ -719,4 +731,19 @@
 {
     return (MediaPort*)pjsua_set_no_snd_dev();
+}
+
+void AudDevManager::setSndDevMode(unsigned mode) const throw(Error)
+{    
+    int capture_dev = 0, playback_dev = 0;
+    pjsua_snd_dev_param param;
+    pj_status_t status = pjsua_get_snd_dev(&capture_dev, &playback_dev);    
+    if (status != PJ_SUCCESS) {
+	PJSUA2_RAISE_ERROR2(status, "AudDevManager::setSndDevMode()");	
+    }
+    pjsua_snd_dev_param_default(&param);
+    param.capture_dev = capture_dev;
+    param.playback_dev = playback_dev;
+    param.mode = mode;
+    PJSUA2_CHECK_EXPR( pjsua_set_snd_dev2(&param) );
 }
 
