Index: /pjproject/trunk/pjmedia/build/Makefile
===================================================================
--- /pjproject/trunk/pjmedia/build/Makefile	(revision 5254)
+++ /pjproject/trunk/pjmedia/build/Makefile	(revision 5255)
@@ -76,11 +76,9 @@
 			vid_port.o vid_stream.o vid_stream_info.o vid_tee.o \
 			wav_player.o wav_playlist.o wav_writer.o wave.o \
-			wsola.o
+			wsola.o audiodev.o videodev.o
 
 export PJMEDIA_CFLAGS += $(_CFLAGS)
 export PJMEDIA_CXXFLAGS += $(_CXXFLAGS)
-export PJMEDIA_LDFLAGS += $(PJMEDIA_VIDEODEV_LDLIB) \
-			  $(PJMEDIA_AUDIODEV_LDLIB) \
-			  $(PJLIB_LDLIB) \
+export PJMEDIA_LDFLAGS += $(PJLIB_LDLIB) \
 			  $(PJLIB_UTIL_LDLIB) \
 			  $(PJNATH_LDLIB) \
@@ -98,5 +96,6 @@
 export PJMEDIA_AUDIODEV_CFLAGS += $(_CFLAGS)
 export PJMEDIA_AUDIODEV_CXXFLAGS += $(_CXXFLAGS)
-export PJMEDIA_AUDIODEV_LDFLAGS += $(PJLIB_LDLIB) \
+export PJMEDIA_AUDIODEV_LDFLAGS += $(PJMEDIA_LDLIB) \
+				   $(PJLIB_LDLIB) \
 				   $(_LDFLAGS)
 
@@ -106,10 +105,11 @@
 #
 export PJMEDIA_VIDEODEV_SRCDIR = ../src/pjmedia-videodev
-export PJMEDIA_VIDEODEV_OBJS +=  errno.o videodev.o avi_dev.o ffmpeg_dev.o \
+export PJMEDIA_VIDEODEV_OBJS += videodev.o errno.o avi_dev.o ffmpeg_dev.o \
 				colorbar_dev.o v4l2_dev.o opengl_dev.o \
 				util.o
 export PJMEDIA_VIDEODEV_CFLAGS += $(_CFLAGS)
 export PJMEDIA_VIDEODEV_CXXFLAGS += $(_CXXFLAGS)
-export PJMEDIA_VIDEODEV_LDFLAGS += $(PJLIB_LDLIB) \
+export PJMEDIA_VIDEODEV_LDFLAGS += $(PJMEDIA_LDLIB) \
+				   $(PJLIB_LDLIB) \
 				   $(_LDFLAGS)
 
@@ -212,5 +212,5 @@
 pjmedia: $(PJMEDIA_LIB)
 $(PJMEDIA_SONAME): $(PJMEDIA_LIB)
-$(PJMEDIA_LIB) $(PJMEDIA_SONAME): $(PJMEDIA_AUDIODEV_LIB) $(PJMEDIA_AUDIODEV_SONAME) $(PJMEDIA_VIDEODEV_LIB) $(PJMEDIA_VIDEODEV_SONAME)
+$(PJMEDIA_LIB) $(PJMEDIA_SONAME):
 	$(MAKE) -f $(RULES_MAK) APP=PJMEDIA app=pjmedia $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
 
@@ -222,10 +222,10 @@
 pjmedia-videodev: $(PJMEDIA_VIDEODEV_LIB)
 $(PJMEDIA_VIDEODEV_SONAME): $(PJMEDIA_VIDEODEV_LIB)
-$(PJMEDIA_VIDEODEV_LIB) $(PJMEDIA_VIDEODEV_SONAME):
+$(PJMEDIA_VIDEODEV_LIB) $(PJMEDIA_VIDEODEV_SONAME): $(PJMEDIA_LIB) $(PJMEDIA_SONAME)
 	$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_VIDEODEV app=pjmedia-videodev $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
 
 pjmedia-audiodev: $(PJMEDIA_AUDIODEV_LIB)
 $(PJMEDIA_AUDIODEV_SONAME): $(PJMEDIA_AUDIODEV_LIB)
-$(PJMEDIA_AUDIODEV_LIB) $(PJMEDIA_AUDIODEV_SONAME):
+$(PJMEDIA_AUDIODEV_LIB) $(PJMEDIA_AUDIODEV_SONAME): $(PJMEDIA_LIB) $(PJMEDIA_SONAME)
 	$(MAKE) -f $(RULES_MAK) APP=PJMEDIA_AUDIODEV app=pjmedia-audiodev $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)
 
Index: /pjproject/trunk/pjmedia/include/pjmedia-audiodev/audiodev.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 5254)
+++ /pjproject/trunk/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 5255)
@@ -23,12 +23,8 @@
 /**
  * @file audiodev.h
- * @brief Audio device API.
+ * @brief Audio subsystem API.
  */
-#include <pjmedia-audiodev/config.h>
-#include <pjmedia-audiodev/errno.h>
-#include <pjmedia/format.h>
-#include <pjmedia/frame.h>
-#include <pjmedia/types.h>
 #include <pj/pool.h>
+#include <pjmedia/audiodev.h>
 
 
@@ -36,463 +32,10 @@
 
 /**
- * @defgroup s2_audio_device_reference Audio Device API Reference
- * @ingroup audio_device_api
+ * @defgroup s2_audio_device_reference Audio Subsystem API Reference
+ * @ingroup audio_subsystem_api
  * @brief API Reference
  * @{
  */
 
-/**
- * Type for device index.
- */
-typedef pj_int32_t pjmedia_aud_dev_index;
-
-/**
- * Device index constants.
- */
-enum
-{
-    /** 
-     * Constant to denote default capture device 
-     */
-    PJMEDIA_AUD_DEFAULT_CAPTURE_DEV = -1,
-
-    /** 
-     * Constant to denote default playback device 
-     */
-    PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV = -2,
-
-    /**
-     * Constant to denote invalid device index.
-     */
-    PJMEDIA_AUD_INVALID_DEV = -3
-};
-
-
-/**
- * This enumeration identifies various audio device capabilities. These audio
- * capabilities indicates what features are supported by the underlying
- * audio device implementation.
- *
- * Applications get these capabilities in the #pjmedia_aud_dev_info structure.
- *
- * Application can also set the specific features/capabilities when opening
- * the audio stream by setting the \a flags member of #pjmedia_aud_param
- * structure.
- *
- * Once audio stream is running, application can also retrieve or set some
- * specific audio capability, by using #pjmedia_aud_stream_get_cap() and
- * #pjmedia_aud_stream_set_cap() and specifying the desired capability. The
- * value of the capability is specified as pointer, and application needs to
- * supply the pointer with the correct value, according to the documentation
- * of each of the capability.
- */
-typedef enum pjmedia_aud_dev_cap
-{
-    /** 
-     * Support for audio formats other than PCM. The value of this capability
-     * is represented by #pjmedia_format structure.
-     */
-    PJMEDIA_AUD_DEV_CAP_EXT_FORMAT = 1,
-
-    /** 
-     * Support for audio input latency control or query. The value of this 
-     * capability is an unsigned integer containing milliseconds value of
-     * the latency.
-     */
-    PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY = 2,
-
-    /** 
-     * Support for audio output latency control or query. The value of this 
-     * capability is an unsigned integer containing milliseconds value of
-     * the latency.
-     */
-    PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY = 4,
-
-    /** 
-     * Support for setting/retrieving the audio input device volume level.
-     * The value of this capability is an unsigned integer representing 
-     * the input audio volume setting in percent.
-     */
-    PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING = 8,
-
-    /** 
-     * Support for setting/retrieving the audio output device volume level.
-     * The value of this capability is an unsigned integer representing 
-     * the output audio volume setting in percent.
-     */
-    PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING = 16,
-
-    /** 
-     * Support for monitoring the current audio input signal volume. 
-     * The value of this capability is an unsigned integer representing 
-     * the audio volume in percent.
-     */
-    PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER = 32,
-
-    /** 
-     * Support for monitoring the current audio output signal volume. 
-     * The value of this capability is an unsigned integer representing 
-     * the audio volume in percent.
-     */
-    PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64,
-
-    /** 
-     * Support for audio input routing. The value of this capability is an 
-     * integer containing #pjmedia_aud_dev_route enumeration.
-     */
-    PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE = 128,
-
-    /** 
-     * Support for audio output routing (e.g. loudspeaker vs earpiece). The
-     * value of this capability is an integer containing #pjmedia_aud_dev_route
-     * enumeration.
-     */
-    PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE = 256,
-
-    /** 
-     * The audio device has echo cancellation feature. The value of this
-     * capability is a pj_bool_t containing boolean PJ_TRUE or PJ_FALSE.
-     */
-    PJMEDIA_AUD_DEV_CAP_EC = 512,
-
-    /** 
-     * The audio device supports setting echo cancellation fail length. The
-     * value of this capability is an unsigned integer representing the
-     * echo tail in milliseconds.
-     */
-    PJMEDIA_AUD_DEV_CAP_EC_TAIL = 1024,
-
-    /** 
-     * The audio device has voice activity detection feature. The value
-     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
-     * PJ_FALSE.
-     */
-    PJMEDIA_AUD_DEV_CAP_VAD = 2048,
-
-    /** 
-     * The audio device has comfort noise generation feature. The value
-     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
-     * PJ_FALSE.
-     */
-    PJMEDIA_AUD_DEV_CAP_CNG = 4096,
-
-    /** 
-     * The audio device has packet loss concealment feature. The value
-     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
-     * PJ_FALSE.
-     */
-    PJMEDIA_AUD_DEV_CAP_PLC = 8192,
-    
-    /**
-     * End of capability
-     */
-    PJMEDIA_AUD_DEV_CAP_MAX = 16384
-
-} pjmedia_aud_dev_cap;
-
-
-/**
- * This enumeration describes audio routing setting.
- */
-typedef enum pjmedia_aud_dev_route
-{
-    /**
-     * Default route, it is the default audio route of the audio framework
-     * backend, as in opening audio device without specifying any route
-     * setting or with specifying neutral route setting.
-     */
-    PJMEDIA_AUD_DEV_ROUTE_DEFAULT = 0,
-
-    /** Route to loudspeaker */
-    PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER = 1,
-
-    /** Route to earpiece */
-    PJMEDIA_AUD_DEV_ROUTE_EARPIECE = 2,
-
-    /** Route to paired Bluetooth device */
-    PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH = 4
-
-} pjmedia_aud_dev_route;
-
-
-/**
- * Device information structure returned by #pjmedia_aud_dev_get_info().
- */
-typedef struct pjmedia_aud_dev_info
-{
-    /** 
-     * The device name 
-     */
-    char name[PJMEDIA_AUD_DEV_INFO_NAME_LEN];
-
-    /** 
-     * Maximum number of input channels supported by this device. If the
-     * value is zero, the device does not support input operation (i.e.
-     * it is a playback only device). 
-     */
-    unsigned input_count;
-
-    /** 
-     * Maximum number of output channels supported by this device. If the
-     * value is zero, the device does not support output operation (i.e. 
-     * it is an input only device).
-     */
-    unsigned output_count;
-
-    /** 
-     * Default sampling rate.
-     */
-    unsigned default_samples_per_sec;
-
-    /** 
-     * The underlying driver name 
-     */
-    char driver[32];
-
-    /** 
-     * Device capabilities, as bitmask combination of #pjmedia_aud_dev_cap.
-     */
-    unsigned caps;
-
-    /** 
-     * Supported audio device routes, as bitmask combination of 
-     * #pjmedia_aud_dev_route. The value may be zero if the device
-     * does not support audio routing.
-     */
-    unsigned routes;
-
-    /** 
-     * Number of audio formats supported by this device. The value may be
-     * zero if the device does not support non-PCM format.
-     */
-    unsigned ext_fmt_cnt;
-
-    /** 
-     * Array of supported extended audio formats 
-     */
-    pjmedia_format ext_fmt[8];
-
-
-} pjmedia_aud_dev_info;
-
-
-/** 
- * This callback is called by player stream when it needs additional data
- * to be played by the device. Application must fill in the whole of output 
- * buffer with audio samples.
- *
- * The frame argument contains the following values:
- *  - timestamp	    Playback timestamp, in samples.
- *  - buf	    Buffer to be filled out by application.
- *  - size	    The size requested in bytes, which will be equal to
- *		    the size of one whole packet.
- *
- * @param user_data User data associated with the stream.
- * @param frame	    Audio frame, which buffer is to be filled in by
- *		    the application.
- *
- * @return	    Returning non-PJ_SUCCESS will cause the audio stream
- *		    to stop
- */
-typedef pj_status_t (*pjmedia_aud_play_cb)(void *user_data,
-					   pjmedia_frame *frame);
-
-/**
- * This callback is called by recorder stream when it has captured the whole
- * packet worth of audio samples.
- *
- * @param user_data User data associated with the stream.
- * @param frame	    Captured frame.
- *
- * @return	    Returning non-PJ_SUCCESS will cause the audio stream
- *		    to stop
- */
-typedef pj_status_t (*pjmedia_aud_rec_cb)(void *user_data,
-					  pjmedia_frame *frame);
-
-/**
- * This structure specifies the parameters to open the audio stream.
- */
-typedef struct pjmedia_aud_param
-{
-    /**
-     * The audio direction. This setting is mandatory.
-     */
-    pjmedia_dir dir;
-
-    /**
-     * The audio recorder device ID. This setting is mandatory if the audio
-     * direction includes input/capture direction.
-     */
-    pjmedia_aud_dev_index rec_id;
-
-    /**
-     * The audio playback device ID. This setting is mandatory if the audio
-     * direction includes output/playback direction.
-     */
-    pjmedia_aud_dev_index play_id;
-
-    /** 
-     * Clock rate/sampling rate. This setting is mandatory. 
-     */
-    unsigned clock_rate;
-
-    /** 
-     * Number of channels. This setting is mandatory. 
-     */
-    unsigned channel_count;
-
-    /** 
-     * Number of samples per frame. This setting is mandatory. 
-     */
-    unsigned samples_per_frame;
-
-    /** 
-     * Number of bits per sample. This setting is mandatory. 
-     */
-    unsigned bits_per_sample;
-
-    /** 
-     * This flags specifies which of the optional settings are valid in this
-     * structure. The flags is bitmask combination of pjmedia_aud_dev_cap.
-     */
-    unsigned flags;
-
-    /** 
-     * Set the audio format. This setting is optional, and will only be used
-     * if PJMEDIA_AUD_DEV_CAP_EXT_FORMAT is set in the flags.
-     */
-    pjmedia_format ext_fmt;
-
-    /**
-     * Input latency, in milliseconds. This setting is optional, and will 
-     * only be used if PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY is set in the flags.
-     */
-    unsigned input_latency_ms;
-
-    /**
-     * Input latency, in milliseconds. This setting is optional, and will 
-     * only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY is set in the flags.
-     */
-    unsigned output_latency_ms;
-
-    /**
-     * Input volume setting, in percent. This setting is optional, and will 
-     * only be used if PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING is set in 
-     * the flags.
-     */
-    unsigned input_vol;
-
-    /**
-     * Output volume setting, in percent. This setting is optional, and will 
-     * only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING is set in 
-     * the flags.
-     */
-    unsigned output_vol;
-
-    /** 
-     * Set the audio input route. This setting is optional, and will only be
-     * used if PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE is set in the flags.
-     */
-    pjmedia_aud_dev_route input_route;
-
-    /** 
-     * Set the audio output route. This setting is optional, and will only be
-     * used if PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE is set in the flags.
-     */
-    pjmedia_aud_dev_route output_route;
-
-    /**
-     * Enable/disable echo canceller, if the device supports it. This setting
-     * is optional, and will only be used if PJMEDIA_AUD_DEV_CAP_EC is set in
-     * the flags.
-     */
-    pj_bool_t ec_enabled;
-
-    /**
-     * Set echo canceller tail length in milliseconds, if the device supports
-     * it. This setting is optional, and will only be used if
-     * PJMEDIA_AUD_DEV_CAP_EC_TAIL is set in the flags.
-     */
-    unsigned ec_tail_ms;
-
-    /** 
-     * Enable/disable PLC. This setting is optional, and will only be used
-     * if PJMEDIA_AUD_DEV_CAP_PLC is set in the flags.
-     */
-    pj_bool_t plc_enabled;
-
-    /** 
-     * Enable/disable CNG. This setting is optional, and will only be used
-     * if PJMEDIA_AUD_DEV_CAP_CNG is set in the flags.
-     */
-    pj_bool_t cng_enabled;
-
-    /** 
-     * Enable/disable VAD. This setting is optional, and will only be used
-     * if PJMEDIA_AUD_DEV_CAP_VAD is set in the flags.
-     */
-    pj_bool_t vad_enabled;
-
-} pjmedia_aud_param;
-
-
-/** Forward declaration for pjmedia_aud_stream */
-typedef struct pjmedia_aud_stream pjmedia_aud_stream;
-
-/** Forward declaration for audio device factory */
-typedef struct pjmedia_aud_dev_factory pjmedia_aud_dev_factory;
-
-/* typedef for factory creation function */
-typedef pjmedia_aud_dev_factory*
-(*pjmedia_aud_dev_factory_create_func_ptr)(pj_pool_factory*);
-
-
-/**
- * Get string info for the specified capability.
- *
- * @param cap		The capability ID.
- * @param p_desc	Optional pointer which will be filled with longer 
- *			description about the capability.
- *
- * @return		Capability name.
- */
-PJ_DECL(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
-					      const char **p_desc);
-
-
-/**
- * Set a capability field value in #pjmedia_aud_param structure. This will
- * also set the flags field for the specified capability in the structure.
- *
- * @param param		The structure.
- * @param cap		The audio capability which value is to be set.
- * @param pval		Pointer to value. Please see the type of value to
- *			be supplied in the pjmedia_aud_dev_cap documentation.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_param_set_cap(pjmedia_aud_param *param,
-					       pjmedia_aud_dev_cap cap,
-					       const void *pval);
-
-
-/**
- * Get a capability field value from #pjmedia_aud_param structure. This
- * function will return PJMEDIA_EAUD_INVCAP error if the flag for that
- * capability is not set in the flags field in the structure.
- *
- * @param param		The structure.
- * @param cap		The audio capability which value is to be retrieved.
- * @param pval		Pointer to value. Please see the type of value to
- *			be supplied in the pjmedia_aud_dev_cap documentation.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_param_get_cap(const pjmedia_aud_param *param,
-					       pjmedia_aud_dev_cap cap,
-					       void *pval);
 
 /**
@@ -559,165 +102,4 @@
 
 /**
- * Refresh the list of sound devices installed in the system. This function
- * will only refresh the list of audio device so all active audio streams will
- * be unaffected. After refreshing the device list, application MUST make sure
- * to update all index references to audio devices (i.e. all variables of type
- * pjmedia_aud_dev_index) before calling any function that accepts audio device
- * index as its parameter.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_dev_refresh(void);
-
-
-/**
- * Get the number of sound devices installed in the system.
- *
- * @return		The number of sound devices installed in the system.
- */
-PJ_DECL(unsigned) pjmedia_aud_dev_count(void);
-
-
-/**
- * Get device information.
- *
- * @param id		The audio device ID.
- * @param info		The device information which will be filled in by this
- *			function once it returns successfully.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
-					      pjmedia_aud_dev_info *info);
-
-
-/**
- * Lookup device index based on the driver and device name.
- *
- * @param drv_name	The driver name.
- * @param dev_name	The device name.
- * @param id		Pointer to store the returned device ID.
- *
- * @return		PJ_SUCCESS if the device can be found.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_dev_lookup(const char *drv_name,
-					    const char *dev_name,
-					    pjmedia_aud_dev_index *id);
-
-
-/**
- * Initialize the audio device parameters with default values for the
- * specified device.
- *
- * @param id		The audio device ID.
- * @param param		The audio device parameters which will be initialized
- *			by this function once it returns successfully.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
-						   pjmedia_aud_param *param);
-
-
-/**
- * Open audio stream object using the specified parameters.
- *
- * @param param		Sound device parameters to be used for the stream.
- * @param rec_cb	Callback to be called on every input frame captured.
- * @param play_cb	Callback to be called everytime the sound device needs
- *			audio frames to be played back.
- * @param user_data	Arbitrary user data, which will be given back in the
- *			callbacks.
- * @param p_strm	Pointer to receive the audio stream.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *param,
-					       pjmedia_aud_rec_cb rec_cb,
-					       pjmedia_aud_play_cb play_cb,
-					       void *user_data,
-					       pjmedia_aud_stream **p_strm);
-
-/**
- * Get the running parameters for the specified audio stream.
- *
- * @param strm		The audio stream.
- * @param param		Audio stream parameters to be filled in by this 
- *			function once it returns successfully.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
-						  pjmedia_aud_param *param);
-
-/**
- * Get the value of a specific capability of the audio stream.
- *
- * @param strm		The audio stream.
- * @param cap		The audio capability which value is to be retrieved.
- * @param value		Pointer to value to be filled in by this function 
- *			once it returns successfully.  Please see the type 
- *			of value to be supplied in the pjmedia_aud_dev_cap
- *			documentation.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
-						pjmedia_aud_dev_cap cap,
-						void *value);
-
-/**
- * Set the value of a specific capability of the audio stream.
- *
- * @param strm		The audio stream.
- * @param cap		The audio capability which value is to be set.
- * @param value		Pointer to value. Please see the type of value to
- *			be supplied in the pjmedia_aud_dev_cap documentation.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
-						pjmedia_aud_dev_cap cap,
-						const void *value);
-
-/**
- * Start the stream.
- *
- * @param strm		The audio stream.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm);
-
-/**
- * Stop the stream.
- *
- * @param strm		The audio stream.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm);
-
-/**
- * Destroy the stream.
- *
- * @param strm		The audio stream.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm);
-
-
-/**
  * @}
  */
Index: /pjproject/trunk/pjmedia/include/pjmedia-videodev/videodev.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-videodev/videodev.h	(revision 5254)
+++ /pjproject/trunk/pjmedia/include/pjmedia-videodev/videodev.h	(revision 5255)
@@ -24,10 +24,5 @@
  * @brief Video device API.
  */
-#include <pjmedia-videodev/config.h>
-#include <pjmedia-videodev/errno.h>
-#include <pjmedia/event.h>
-#include <pjmedia/frame.h>
-#include <pjmedia/format.h>
-#include <pj/pool.h>
+#include <pjmedia/videodev.h>
 
 
@@ -35,504 +30,10 @@
 
 /**
- * @defgroup video_device_reference Video Device API Reference
- * @ingroup video_device_api
+ * @defgroup video_device_reference Video Subsystem API Reference
+ * @ingroup video_subsystem_api
  * @brief API Reference
  * @{
  */
  
-/**
- * Type for device index.
- */
-typedef pj_int32_t pjmedia_vid_dev_index;
-
-/**
- * Enumeration of window handle type.
- */
-typedef enum pjmedia_vid_dev_hwnd_type
-{
-    /**
-     * Type none.
-     */
-    PJMEDIA_VID_DEV_HWND_TYPE_NONE,
-
-    /**
-     * Native window handle on Windows.
-     */
-    PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS,
-
-    /**
-     * Native view on iOS.
-     */
-    PJMEDIA_VID_DEV_HWND_TYPE_IOS,
-
-    /**
-     * Native window handle on Android.
-     */
-    PJMEDIA_VID_DEV_HWND_TYPE_ANDROID
-
-} pjmedia_vid_dev_hwnd_type;
-
-/**
- * Type for window handle.
- */
-typedef struct pjmedia_vid_dev_hwnd
-{
-    /**
-     * The window handle type.
-     */
-    pjmedia_vid_dev_hwnd_type type;
-
-    /**
-     * The window handle.
-     */
-    union
-    {
-	struct {
-	    void    *hwnd;	/**< HWND     	*/
-	} win;
-	struct {
-	    void    *window;    /**< Window	*/
-	    void    *display;   /**< Display	*/
-	} x11;
-	struct {
-	    void    *window;    /**< Window	*/
-	} cocoa;
-	struct {
-	    void    *window;    /**< Window	*/
-	} ios;
-	struct {
-	    void    *window;    /**< Native window */
-	} android;
-	void 	    *window;
-    } info;
-
-} pjmedia_vid_dev_hwnd;
-
-/**
- * Parameter for switching device with PJMEDIA_VID_DEV_CAP_SWITCH capability.
- * Initialize this with pjmedia_vid_dev_switch_param_default()
- */
-typedef struct pjmedia_vid_dev_switch_param
-{
-    /**
-     * Target device ID to switch to. Once the switching is successful, the
-     * video stream will use this device and the old device will be closed.
-     */
-    pjmedia_vid_dev_index target_id;
-
-} pjmedia_vid_dev_switch_param;
-
-
-/**
- * Enumeration of window flags.
- */
-typedef enum pjmedia_vid_dev_wnd_flag
-{
-    /**
-     * Window with border.
-     */
-    PJMEDIA_VID_DEV_WND_BORDER = 1,
-
-    /**
-     * Window can be resized.
-     */
-    PJMEDIA_VID_DEV_WND_RESIZABLE = 2
-
-} pjmedia_vid_dev_wnd_flag;
-
-
-/**
- * Device index constants.
- */
-enum pjmedia_vid_dev_std_index
-{
-    /**
-     * Constant to denote default capture device
-     */
-    PJMEDIA_VID_DEFAULT_CAPTURE_DEV = -1,
-
-    /**
-     * Constant to denote default render device
-     */
-    PJMEDIA_VID_DEFAULT_RENDER_DEV = -2,
-
-    /**
-     * Constant to denote invalid device index.
-     */
-    PJMEDIA_VID_INVALID_DEV = -3
-};
-
-
-/**
- * This enumeration identifies various video device capabilities. These video
- * capabilities indicates what features are supported by the underlying
- * video device implementation.
- *
- * Applications get these capabilities in the #pjmedia_vid_dev_info structure.
- *
- * Application can also set the specific features/capabilities when opening
- * the video stream by setting the \a flags member of #pjmedia_vid_dev_param
- * structure.
- *
- * Once video stream is running, application can also retrieve or set some
- * specific video capability, by using #pjmedia_vid_dev_stream_get_cap() and
- * #pjmedia_vid_dev_stream_set_cap() and specifying the desired capability. The
- * value of the capability is specified as pointer, and application needs to
- * supply the pointer with the correct value, according to the documentation
- * of each of the capability.
- */
-typedef enum pjmedia_vid_dev_cap
-{
-    /**
-     * Support for video formats. The value of this capability
-     * is represented by #pjmedia_format structure.
-     */
-    PJMEDIA_VID_DEV_CAP_FORMAT = 1,
-
-    /**
-     * Support for video input scaling
-     */
-    PJMEDIA_VID_DEV_CAP_INPUT_SCALE = 2,
-
-    /**
-     * Support for returning the native window handle of the video window.
-     * For renderer, this means the window handle of the renderer window,
-     * while for capture, this means the window handle of the native preview,
-     * only if the device supports  PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
-     * capability.
-     *
-     * The value of this capability is pointer to pjmedia_vid_dev_hwnd
-     * structure.
-     */
-    PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW = 4,
-
-    /**
-     * Support for resizing video output. This capability SHOULD be 
-     * implemented by renderer, to alter the video output dimension on the fly.
-     * Value is pjmedia_rect_size. 
-     */
-    PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE = 8,
-
-    /**
-     * Support for setting the video window's position.
-     * Value is pjmedia_coord specifying the window's new coordinate.
-     */
-    PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION = 16,
-
-    /**
-     * Support for setting the video output's visibility.
-     * The value of this capability is a pj_bool_t containing boolean
-     * PJ_TRUE or PJ_FALSE.
-     */
-    PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE = 32,
-
-    /**
-     * Support for native preview capability in capture devices. Value is
-     * pj_bool_t. With native preview, capture device can be instructed to
-     * show or hide a preview window showing video directly from the camera
-     * by setting this capability to PJ_TRUE or PJ_FALSE. Once the preview
-     * is started, application may use PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW
-     * capability to query the video window.
-     *
-     * The value of this capability is a pj_bool_t containing boolean
-     * PJ_TRUE or PJ_FALSE.
-     */
-    PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW = 64,
-
-    /**
-     * Support for changing video orientation. For a renderer device,
-     * changing video orientation in will potentially affect the size of
-     * render window, i.e: width and height swap. For a capture device,
-     * the video will be rotated but the size of the video frame
-     * will stay the same, so the video may be resized or stretched.
-     *
-     * The value of this capability is pjmedia_orient.
-     */
-    PJMEDIA_VID_DEV_CAP_ORIENTATION = 128,
-
-    /**
-     * Support for fast switching to another device. A video stream with this
-     * capability allows replacing of its underlying device with another
-     * device, saving the user from opening a new video stream and gets a much
-     * faster and smoother switching action.
-     *
-     * Note that even when this capability is supported by a device, it may
-     * not be able to switch to arbitrary device. Application must always
-     * check the return value of the operation to verify that switching has
-     * occurred.
-     *
-     * This capability is currently write-only (i.e. set-only).
-     *
-     * The value of this capability is pointer to pjmedia_vid_dev_switch_param
-     * structure.
-     */
-    PJMEDIA_VID_DEV_CAP_SWITCH = 256,
-
-    /**
-     * Support for setting the output video window's flags.
-     * The value of this capability is a bitmask combination of
-     * #pjmedia_vid_dev_wnd_flag.
-     */
-    PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS = 512,
-
-    /**
-     * End of standard capability
-     */
-    PJMEDIA_VID_DEV_CAP_MAX = 16384
-
-} pjmedia_vid_dev_cap;
-
-/**
- * Device information structure returned by #pjmedia_vid_dev_get_info().
- */
-typedef struct pjmedia_vid_dev_info
-{
-    /** The device ID */
-    pjmedia_vid_dev_index id;
-
-    /** The device name */
-    char name[64];
-
-    /** The underlying driver name */
-    char driver[32];
-
-    /** 
-     * The supported direction of the video device, i.e. whether it supports 
-     * capture only, render only, or both.
-     */
-    pjmedia_dir dir;
-
-    /**
-     * Specify whether the device supports callback. Devices that implement
-     * "active interface" will actively call the callbacks to give or ask for
-     * video frames. If the device doesn't support callback, application
-     * must actively request or give video frames from/to the device by using
-     * pjmedia_vid_dev_stream_get_frame()/pjmedia_vid_dev_stream_put_frame().
-     */
-    pj_bool_t has_callback;
-
-    /** Device capabilities, as bitmask combination of #pjmedia_vid_dev_cap */
-    unsigned caps;
-
-    /** Number of video formats supported by this device */
-    unsigned fmt_cnt;
-
-    /** 
-     * Array of supported video formats. Some fields in each supported video
-     * format may be set to zero or of "unknown" value, to indicate that the
-     * value is unknown or should be ignored. When these value are not set
-     * to zero, it indicates that the exact format combination is being used. 
-     */
-    pjmedia_format fmt[PJMEDIA_VID_DEV_INFO_FMT_CNT];
-
-} pjmedia_vid_dev_info;
-
-
-/** Forward declaration for pjmedia_vid_dev_stream */
-typedef struct pjmedia_vid_dev_stream pjmedia_vid_dev_stream;
-
-typedef struct pjmedia_vid_dev_cb
-{
-    /**
-    * This callback is called by capturer stream when it has captured the
-    * whole packet worth of video samples.
-    *
-    * @param stream	   The video stream.
-    * @param user_data     User data associated with the stream.
-    * @param frame         Captured frame.
-    *
-    * @return              Returning non-PJ_SUCCESS will cause the video
-    *                      stream to stop
-    */
-    pj_status_t (*capture_cb)(pjmedia_vid_dev_stream *stream,
-		              void *user_data,
-                              pjmedia_frame *frame);
-
-    /**
-    * This callback is called by renderer stream when it needs additional
-    * data to be rendered by the device. Application must fill in the whole
-    * of output buffer with video samples.
-    *
-    * The frame argument contains the following values:
-    *  - timestamp         Rendering timestamp, in samples.
-    *  - buf               Buffer to be filled out by application.
-    *  - size              The size requested in bytes, which will be equal
-    *                      to the size of one whole packet.
-    *
-    * @param stream	   The video stream.
-    * @param user_data     User data associated with the stream.
-    * @param frame         Video frame, which buffer is to be filled in by
-    *                      the application.
-    *
-    * @return              Returning non-PJ_SUCCESS will cause the video 
-    *                      stream to stop
-    */
-    pj_status_t (*render_cb)(pjmedia_vid_dev_stream *stream,
-			     void *user_data,
-                             pjmedia_frame *frame);
-
-} pjmedia_vid_dev_cb;
-
-
-/**
- * This structure specifies the parameters to open the video stream.
- */
-typedef struct pjmedia_vid_dev_param
-{
-    /**
-     * The video direction. This setting is mandatory.
-     */
-    pjmedia_dir dir;
-
-    /**
-     * The video capture device ID. This setting is mandatory if the video
-     * direction includes input/capture direction.
-     */
-    pjmedia_vid_dev_index cap_id;
-
-    /**
-     * The video render device ID. This setting is mandatory if the video
-     * direction includes output/render direction.
-     */
-    pjmedia_vid_dev_index rend_id;
-
-    /** 
-     * Video clock rate. This setting is mandatory if the video
-     * direction includes input/capture direction
-     */
-    unsigned clock_rate;
-
-    /**
-     * Video frame rate. This setting is mandatory if the video
-     * direction includes input/capture direction
-     */
-//    pjmedia_ratio frame_rate;
-
-    /**
-     * This flags specifies which of the optional settings are valid in this
-     * structure. The flags is bitmask combination of pjmedia_vid_dev_cap.
-     */
-    unsigned flags;
-
-    /**
-     * Set the video format. This setting is mandatory.
-     */
-    pjmedia_format fmt;
-
-    /**
-     * Window for the renderer to display the video. This setting is optional,
-     * and will only be used if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW is set in 
-     * the flags.
-     */
-    pjmedia_vid_dev_hwnd window;
-
-    /**
-     * Video display size. This setting is optional, and will only be used 
-     * if PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE is set in the flags.
-     */
-    pjmedia_rect_size disp_size;
-
-    /**
-     * Video window position. This setting is optional, and will only be used
-     * if PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION is set in the flags.
-     */
-    pjmedia_coord window_pos;
-
-    /**
-     * Video window's visibility. This setting is optional, and will only be
-     * used if PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE is set in the flags.
-     */
-    pj_bool_t window_hide;
-
-    /**
-     * Enable built-in preview. This setting is optional and is only used
-     * if PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW capability is supported and
-     * set in the flags.
-     */
-    pj_bool_t native_preview;
-
-    /**
-     * Video orientation. This setting is optional and is only used if
-     * PJMEDIA_VID_DEV_CAP_ORIENTATION capability is supported and is
-     * set in the flags.
-     */
-    pjmedia_orient orient;
-
-    /**
-     * Video window flags. This setting is optional, and will only be used
-     * if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS is set in the flags.
-     */
-    unsigned window_flags;
-
-} pjmedia_vid_dev_param;
-
-
-/** Forward declaration for video device factory */
-typedef struct pjmedia_vid_dev_factory pjmedia_vid_dev_factory;
-
-/* typedef for factory creation function */
-typedef pjmedia_vid_dev_factory*
-(*pjmedia_vid_dev_factory_create_func_ptr)(pj_pool_factory*);
-
-/**
- * Initialize pjmedia_vid_dev_switch_param.
- *
- * @param p	    Parameter to be initialized.
- */
-PJ_INLINE(void)
-pjmedia_vid_dev_switch_param_default(pjmedia_vid_dev_switch_param *p)
-{
-    pj_bzero(p, sizeof(*p));
-    p->target_id = PJMEDIA_VID_INVALID_DEV;
-}
-
-/**
- * Get string info for the specified capability.
- *
- * @param cap       The capability ID.
- * @param p_desc    Optional pointer which will be filled with longer
- *                  description about the capability.
- *
- * @return          Capability name.
- */
-PJ_DECL(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
-                                              const char **p_desc);
-
-
-/**
- * Set a capability field value in #pjmedia_vid_dev_param structure. This will
- * also set the flags field for the specified capability in the structure.
- *
- * @param param     The structure.
- * @param cap       The video capability which value is to be set.
- * @param pval      Pointer to value. Please see the type of value to
- *                  be supplied in the pjmedia_vid_dev_cap documentation.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t)
-pjmedia_vid_dev_param_set_cap(pjmedia_vid_dev_param *param,
-                              pjmedia_vid_dev_cap cap,
-                              const void *pval);
-
-
-/**
- * Get a capability field value from #pjmedia_vid_dev_param structure. This
- * function will return PJMEDIA_EVID_INVCAP error if the flag for that
- * capability is not set in the flags field in the structure.
- *
- * @param param     The structure.
- * @param cap       The video capability which value is to be retrieved.
- * @param pval      Pointer to value. Please see the type of value to
- *                  be supplied in the pjmedia_vid_dev_cap documentation.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t)
-pjmedia_vid_dev_param_get_cap(const pjmedia_vid_dev_param *param,
-                              pjmedia_vid_dev_cap cap,
-                              void *pval);
 
 /**
@@ -611,224 +112,4 @@
 
 /**
- * Refresh the list of video devices installed in the system. This function
- * will only refresh the list of videoo device so all active video streams will
- * be unaffected. After refreshing the device list, application MUST make sure
- * to update all index references to video devices (i.e. all variables of type
- * pjmedia_vid_dev_index) before calling any function that accepts video device
- * index as its parameter.
- *
- * @return		PJ_SUCCESS on successful operation or the appropriate
- *			error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_refresh(void);
-
-
-/**
- * Get the number of video devices installed in the system.
- *
- * @return          The number of video devices installed in the system.
- */
-PJ_DECL(unsigned) pjmedia_vid_dev_count(void);
-
-
-/**
- * Get device information.
- *
- * @param id        The video device ID.
- * @param info      The device information which will be filled in by this
- *                  function once it returns successfully.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
-                                              pjmedia_vid_dev_info *info);
-
-
-/**
- * Lookup device index based on the driver and device name.
- *
- * @param drv_name  The driver name.
- * @param dev_name  The device name.
- * @param id        Pointer to store the returned device ID.
- *
- * @return          PJ_SUCCESS if the device can be found.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_lookup(const char *drv_name,
-                                            const char *dev_name,
-                                            pjmedia_vid_dev_index *id);
-
-
-/**
- * Initialize the video device parameters with default values for the
- * specified device.
- *
- * @param id        The video device ID.
- * @param param     The video device parameters which will be initialized
- *                  by this function once it returns successfully.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t)
-pjmedia_vid_dev_default_param(pj_pool_t *pool,
-                              pjmedia_vid_dev_index id,
-                              pjmedia_vid_dev_param *param);
-
-
-/**
- * Open video stream object using the specified parameters. If stream is
- * created successfully, this function will return PJ_SUCCESS and the
- * stream pointer will be returned in the p_strm argument.
- *
- * The opened stream may have been opened with different size and fps
- * than the requested values in the \a param argument. Application should
- * check the actual size and fps that the stream was opened with by inspecting
- * the values in the \a param argument and see if they have changed. Also
- * if the device ID in the \a param specifies default device, it may be
- * replaced with the actual device ID upon return.
- *
- * @param param         On input, it specifies the video device parameters
- *                      to be used for the stream. On output, this will be
- *                      set to the actual video device parameters used to
- *                      open the stream.
- * @param cb            Pointer to structure containing video stream
- *                      callbacks.
- * @param user_data     Arbitrary user data, which will be given back in the
- *                      callbacks.
- * @param p_strm        Pointer to receive the video stream.
- *
- * @return              PJ_SUCCESS on successful operation or the appropriate
- *                      error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_create(
-					    pjmedia_vid_dev_param *param,
-					    const pjmedia_vid_dev_cb *cb,
-					    void *user_data,
-					    pjmedia_vid_dev_stream **p_strm);
-
-/**
- * Get the running parameters for the specified video stream.
- *
- * @param strm      The video stream.
- * @param param     Video stream parameters to be filled in by this
- *                  function once it returns successfully.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_param(
-					    pjmedia_vid_dev_stream *strm,
-                                            pjmedia_vid_dev_param *param);
-
-/**
- * Get the value of a specific capability of the video stream.
- *
- * @param strm      The video stream.
- * @param cap       The video capability which value is to be retrieved.
- * @param value     Pointer to value to be filled in by this function
- *                  once it returns successfully.  Please see the type
- *                  of value to be supplied in the pjmedia_vid_dev_cap
- *                  documentation.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_cap(
-					    pjmedia_vid_dev_stream *strm,
-					    pjmedia_vid_dev_cap cap,
-                                            void *value);
-
-/**
- * Set the value of a specific capability of the video stream.
- *
- * @param strm      The video stream.
- * @param cap       The video capability which value is to be set.
- * @param value     Pointer to value. Please see the type of value to
- *                  be supplied in the pjmedia_vid_dev_cap documentation.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_set_cap(
-					    pjmedia_vid_dev_stream *strm,
-					    pjmedia_vid_dev_cap cap,
-					    const void *value);
-
-/**
- * Start the stream.
- *
- * @param strm      The video stream.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
-					    pjmedia_vid_dev_stream *strm);
-
-/**
- * Query whether the stream has been started.
- *
- * @param strm	    The video stream
- *
- * @return	    PJ_TRUE if the video stream has been started.
- */
-PJ_DECL(pj_bool_t) pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm);
-
-
-/**
- * Request one frame from the stream. Application needs to call this function
- * periodically only if the stream doesn't support "active interface", i.e.
- * the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
- *
- * @param strm      The video stream.
- * @param frame	    The video frame to be filled by the device.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_frame(
-					    pjmedia_vid_dev_stream *strm,
-                                            pjmedia_frame *frame);
-
-/**
- * Put one frame to the stream. Application needs to call this function
- * periodically only if the stream doesn't support "active interface", i.e.
- * the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
- *
- * @param strm      The video stream.
- * @param frame	    The video frame to put to the device.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_put_frame(
-					    pjmedia_vid_dev_stream *strm,
-                                            const pjmedia_frame *frame);
-
-/**
- * Stop the stream.
- *
- * @param strm      The video stream.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_stop(
-					    pjmedia_vid_dev_stream *strm);
-
-/**
- * Destroy the stream.
- *
- * @param strm      The video stream.
- *
- * @return          PJ_SUCCESS on successful operation or the appropriate
- *                  error code.
- */
-PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_destroy(
-					    pjmedia_vid_dev_stream *strm);
-
-
-/**
  * @}
  */
Index: /pjproject/trunk/pjmedia/include/pjmedia/audiodev.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/audiodev.h	(revision 5255)
+++ /pjproject/trunk/pjmedia/include/pjmedia/audiodev.h	(revision 5255)
@@ -0,0 +1,728 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJMEDIA_AUDIO_DEV_H__
+#define __PJMEDIA_AUDIO_DEV_H__
+
+/**
+ * @file audiodev.h
+ * @brief Audio device API.
+ */
+#include <pjmedia-audiodev/config.h>
+#include <pjmedia-audiodev/errno.h>
+#include <pjmedia/format.h>
+#include <pjmedia/frame.h>
+#include <pjmedia/types.h>
+#include <pj/pool.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup s2_audio_device_reference Audio Device API Reference
+ * @ingroup audio_device_api
+ * @brief API Reference
+ * @{
+ */
+
+/**
+ * Type for device index.
+ */
+typedef pj_int32_t pjmedia_aud_dev_index;
+
+/**
+ * Device index constants.
+ */
+enum
+{
+    /** 
+     * Constant to denote default capture device 
+     */
+    PJMEDIA_AUD_DEFAULT_CAPTURE_DEV = -1,
+
+    /** 
+     * Constant to denote default playback device 
+     */
+    PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV = -2,
+
+    /**
+     * Constant to denote invalid device index.
+     */
+    PJMEDIA_AUD_INVALID_DEV = -3
+};
+
+
+#define PJMEDIA_AUD_MAX_DRIVERS	16
+#define PJMEDIA_AUD_MAX_DEVS	64
+
+
+/** Forward declaration for pjmedia_aud_stream */
+typedef struct pjmedia_aud_stream pjmedia_aud_stream;
+
+/** Forward declaration for audio device factory */
+typedef struct pjmedia_aud_dev_factory pjmedia_aud_dev_factory;
+
+/* typedef for factory creation function */
+typedef pjmedia_aud_dev_factory*
+(*pjmedia_aud_dev_factory_create_func_ptr)(pj_pool_factory*);
+
+
+/* Audio driver structure */
+typedef struct pjmedia_aud_driver
+{
+    pjmedia_aud_dev_factory_create_func_ptr create; /* Creation function    */
+    pjmedia_aud_dev_factory *f;		  /* Factory instance		    */
+    char		     name[32];	  /* Driver name		    */
+    unsigned		     dev_cnt;	  /* Number of devices		    */
+    unsigned		     start_idx;	  /* Start index in global list	    */
+    int			     rec_dev_idx; /* Default capture device.	    */
+    int			     play_dev_idx;/* Default playback device	    */
+    int			     dev_idx;	  /* Default device.		    */
+} pjmedia_aud_driver;
+
+
+/* Audio subsystem structure */
+typedef struct pjmedia_aud_subsys
+{
+    unsigned	     	init_count;	/* How many times init() is called  */
+    pj_pool_factory    *pf;		/* The pool factory.		    */
+
+    unsigned	     	drv_cnt;	/* Number of drivers.		    */
+    pjmedia_aud_driver  drv[PJMEDIA_AUD_MAX_DRIVERS];/* Array of drivers.   */
+
+    unsigned	     	dev_cnt;	/* Total number of devices.	    */
+    pj_uint32_t	     	dev_list[PJMEDIA_AUD_MAX_DEVS];/* Array of dev IDs. */
+
+} pjmedia_aud_subsys;
+
+
+/**
+ * This enumeration identifies various audio device capabilities. These audio
+ * capabilities indicates what features are supported by the underlying
+ * audio device implementation.
+ *
+ * Applications get these capabilities in the #pjmedia_aud_dev_info structure.
+ *
+ * Application can also set the specific features/capabilities when opening
+ * the audio stream by setting the \a flags member of #pjmedia_aud_param
+ * structure.
+ *
+ * Once audio stream is running, application can also retrieve or set some
+ * specific audio capability, by using #pjmedia_aud_stream_get_cap() and
+ * #pjmedia_aud_stream_set_cap() and specifying the desired capability. The
+ * value of the capability is specified as pointer, and application needs to
+ * supply the pointer with the correct value, according to the documentation
+ * of each of the capability.
+ */
+typedef enum pjmedia_aud_dev_cap
+{
+    /** 
+     * Support for audio formats other than PCM. The value of this capability
+     * is represented by #pjmedia_format structure.
+     */
+    PJMEDIA_AUD_DEV_CAP_EXT_FORMAT = 1,
+
+    /** 
+     * Support for audio input latency control or query. The value of this 
+     * capability is an unsigned integer containing milliseconds value of
+     * the latency.
+     */
+    PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY = 2,
+
+    /** 
+     * Support for audio output latency control or query. The value of this 
+     * capability is an unsigned integer containing milliseconds value of
+     * the latency.
+     */
+    PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY = 4,
+
+    /** 
+     * Support for setting/retrieving the audio input device volume level.
+     * The value of this capability is an unsigned integer representing 
+     * the input audio volume setting in percent.
+     */
+    PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING = 8,
+
+    /** 
+     * Support for setting/retrieving the audio output device volume level.
+     * The value of this capability is an unsigned integer representing 
+     * the output audio volume setting in percent.
+     */
+    PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING = 16,
+
+    /** 
+     * Support for monitoring the current audio input signal volume. 
+     * The value of this capability is an unsigned integer representing 
+     * the audio volume in percent.
+     */
+    PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER = 32,
+
+    /** 
+     * Support for monitoring the current audio output signal volume. 
+     * The value of this capability is an unsigned integer representing 
+     * the audio volume in percent.
+     */
+    PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64,
+
+    /** 
+     * Support for audio input routing. The value of this capability is an 
+     * integer containing #pjmedia_aud_dev_route enumeration.
+     */
+    PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE = 128,
+
+    /** 
+     * Support for audio output routing (e.g. loudspeaker vs earpiece). The
+     * value of this capability is an integer containing #pjmedia_aud_dev_route
+     * enumeration.
+     */
+    PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE = 256,
+
+    /** 
+     * The audio device has echo cancellation feature. The value of this
+     * capability is a pj_bool_t containing boolean PJ_TRUE or PJ_FALSE.
+     */
+    PJMEDIA_AUD_DEV_CAP_EC = 512,
+
+    /** 
+     * The audio device supports setting echo cancellation fail length. The
+     * value of this capability is an unsigned integer representing the
+     * echo tail in milliseconds.
+     */
+    PJMEDIA_AUD_DEV_CAP_EC_TAIL = 1024,
+
+    /** 
+     * The audio device has voice activity detection feature. The value
+     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
+     * PJ_FALSE.
+     */
+    PJMEDIA_AUD_DEV_CAP_VAD = 2048,
+
+    /** 
+     * The audio device has comfort noise generation feature. The value
+     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
+     * PJ_FALSE.
+     */
+    PJMEDIA_AUD_DEV_CAP_CNG = 4096,
+
+    /** 
+     * The audio device has packet loss concealment feature. The value
+     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
+     * PJ_FALSE.
+     */
+    PJMEDIA_AUD_DEV_CAP_PLC = 8192,
+    
+    /**
+     * End of capability
+     */
+    PJMEDIA_AUD_DEV_CAP_MAX = 16384
+
+} pjmedia_aud_dev_cap;
+
+
+/**
+ * This enumeration describes audio routing setting.
+ */
+typedef enum pjmedia_aud_dev_route
+{
+    /**
+     * Default route, it is the default audio route of the audio framework
+     * backend, as in opening audio device without specifying any route
+     * setting or with specifying neutral route setting.
+     */
+    PJMEDIA_AUD_DEV_ROUTE_DEFAULT = 0,
+
+    /** Route to loudspeaker */
+    PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER = 1,
+
+    /** Route to earpiece */
+    PJMEDIA_AUD_DEV_ROUTE_EARPIECE = 2,
+
+    /** Route to paired Bluetooth device */
+    PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH = 4
+
+} pjmedia_aud_dev_route;
+
+
+/**
+ * Device information structure returned by #pjmedia_aud_dev_get_info().
+ */
+typedef struct pjmedia_aud_dev_info
+{
+    /** 
+     * The device name 
+     */
+    char name[PJMEDIA_AUD_DEV_INFO_NAME_LEN];
+
+    /** 
+     * Maximum number of input channels supported by this device. If the
+     * value is zero, the device does not support input operation (i.e.
+     * it is a playback only device). 
+     */
+    unsigned input_count;
+
+    /** 
+     * Maximum number of output channels supported by this device. If the
+     * value is zero, the device does not support output operation (i.e. 
+     * it is an input only device).
+     */
+    unsigned output_count;
+
+    /** 
+     * Default sampling rate.
+     */
+    unsigned default_samples_per_sec;
+
+    /** 
+     * The underlying driver name 
+     */
+    char driver[32];
+
+    /** 
+     * Device capabilities, as bitmask combination of #pjmedia_aud_dev_cap.
+     */
+    unsigned caps;
+
+    /** 
+     * Supported audio device routes, as bitmask combination of 
+     * #pjmedia_aud_dev_route. The value may be zero if the device
+     * does not support audio routing.
+     */
+    unsigned routes;
+
+    /** 
+     * Number of audio formats supported by this device. The value may be
+     * zero if the device does not support non-PCM format.
+     */
+    unsigned ext_fmt_cnt;
+
+    /** 
+     * Array of supported extended audio formats 
+     */
+    pjmedia_format ext_fmt[8];
+
+
+} pjmedia_aud_dev_info;
+
+
+/** 
+ * This callback is called by player stream when it needs additional data
+ * to be played by the device. Application must fill in the whole of output 
+ * buffer with audio samples.
+ *
+ * The frame argument contains the following values:
+ *  - timestamp	    Playback timestamp, in samples.
+ *  - buf	    Buffer to be filled out by application.
+ *  - size	    The size requested in bytes, which will be equal to
+ *		    the size of one whole packet.
+ *
+ * @param user_data User data associated with the stream.
+ * @param frame	    Audio frame, which buffer is to be filled in by
+ *		    the application.
+ *
+ * @return	    Returning non-PJ_SUCCESS will cause the audio stream
+ *		    to stop
+ */
+typedef pj_status_t (*pjmedia_aud_play_cb)(void *user_data,
+					   pjmedia_frame *frame);
+
+/**
+ * This callback is called by recorder stream when it has captured the whole
+ * packet worth of audio samples.
+ *
+ * @param user_data User data associated with the stream.
+ * @param frame	    Captured frame.
+ *
+ * @return	    Returning non-PJ_SUCCESS will cause the audio stream
+ *		    to stop
+ */
+typedef pj_status_t (*pjmedia_aud_rec_cb)(void *user_data,
+					  pjmedia_frame *frame);
+
+/**
+ * This structure specifies the parameters to open the audio stream.
+ */
+typedef struct pjmedia_aud_param
+{
+    /**
+     * The audio direction. This setting is mandatory.
+     */
+    pjmedia_dir dir;
+
+    /**
+     * The audio recorder device ID. This setting is mandatory if the audio
+     * direction includes input/capture direction.
+     */
+    pjmedia_aud_dev_index rec_id;
+
+    /**
+     * The audio playback device ID. This setting is mandatory if the audio
+     * direction includes output/playback direction.
+     */
+    pjmedia_aud_dev_index play_id;
+
+    /** 
+     * Clock rate/sampling rate. This setting is mandatory. 
+     */
+    unsigned clock_rate;
+
+    /** 
+     * Number of channels. This setting is mandatory. 
+     */
+    unsigned channel_count;
+
+    /** 
+     * Number of samples per frame. This setting is mandatory. 
+     */
+    unsigned samples_per_frame;
+
+    /** 
+     * Number of bits per sample. This setting is mandatory. 
+     */
+    unsigned bits_per_sample;
+
+    /** 
+     * This flags specifies which of the optional settings are valid in this
+     * structure. The flags is bitmask combination of pjmedia_aud_dev_cap.
+     */
+    unsigned flags;
+
+    /** 
+     * Set the audio format. This setting is optional, and will only be used
+     * if PJMEDIA_AUD_DEV_CAP_EXT_FORMAT is set in the flags.
+     */
+    pjmedia_format ext_fmt;
+
+    /**
+     * Input latency, in milliseconds. This setting is optional, and will 
+     * only be used if PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY is set in the flags.
+     */
+    unsigned input_latency_ms;
+
+    /**
+     * Input latency, in milliseconds. This setting is optional, and will 
+     * only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY is set in the flags.
+     */
+    unsigned output_latency_ms;
+
+    /**
+     * Input volume setting, in percent. This setting is optional, and will 
+     * only be used if PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING is set in 
+     * the flags.
+     */
+    unsigned input_vol;
+
+    /**
+     * Output volume setting, in percent. This setting is optional, and will 
+     * only be used if PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING is set in 
+     * the flags.
+     */
+    unsigned output_vol;
+
+    /** 
+     * Set the audio input route. This setting is optional, and will only be
+     * used if PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE is set in the flags.
+     */
+    pjmedia_aud_dev_route input_route;
+
+    /** 
+     * Set the audio output route. This setting is optional, and will only be
+     * used if PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE is set in the flags.
+     */
+    pjmedia_aud_dev_route output_route;
+
+    /**
+     * Enable/disable echo canceller, if the device supports it. This setting
+     * is optional, and will only be used if PJMEDIA_AUD_DEV_CAP_EC is set in
+     * the flags.
+     */
+    pj_bool_t ec_enabled;
+
+    /**
+     * Set echo canceller tail length in milliseconds, if the device supports
+     * it. This setting is optional, and will only be used if
+     * PJMEDIA_AUD_DEV_CAP_EC_TAIL is set in the flags.
+     */
+    unsigned ec_tail_ms;
+
+    /** 
+     * Enable/disable PLC. This setting is optional, and will only be used
+     * if PJMEDIA_AUD_DEV_CAP_PLC is set in the flags.
+     */
+    pj_bool_t plc_enabled;
+
+    /** 
+     * Enable/disable CNG. This setting is optional, and will only be used
+     * if PJMEDIA_AUD_DEV_CAP_CNG is set in the flags.
+     */
+    pj_bool_t cng_enabled;
+
+    /** 
+     * Enable/disable VAD. This setting is optional, and will only be used
+     * if PJMEDIA_AUD_DEV_CAP_VAD is set in the flags.
+     */
+    pj_bool_t vad_enabled;
+
+} pjmedia_aud_param;
+
+
+/**
+ * Get the audio subsystem.
+ *
+ * @return		The audio subsystem.
+ */
+PJ_DECL(pjmedia_aud_subsys*) pjmedia_get_aud_subsys(void);
+
+/**
+ * Initialize the audio driver.
+ *
+ * @param drv_idx	The index of the audio driver.
+ * @param refresh	Specify non-zero to refresh the audio driver.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_driver_init(unsigned drv_idx,
+					     pj_bool_t refresh);
+
+/**
+ * Deinitialize the audio driver.
+ *
+ * @param drv_idx	The index of the audio driver.
+ */
+PJ_DECL(void) pjmedia_aud_driver_deinit(unsigned drv_idx);
+
+
+/**
+ * Get string info for the specified capability.
+ *
+ * @param cap		The capability ID.
+ * @param p_desc	Optional pointer which will be filled with longer 
+ *			description about the capability.
+ *
+ * @return		Capability name.
+ */
+PJ_DECL(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
+					      const char **p_desc);
+
+
+/**
+ * Set a capability field value in #pjmedia_aud_param structure. This will
+ * also set the flags field for the specified capability in the structure.
+ *
+ * @param param		The structure.
+ * @param cap		The audio capability which value is to be set.
+ * @param pval		Pointer to value. Please see the type of value to
+ *			be supplied in the pjmedia_aud_dev_cap documentation.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_param_set_cap(pjmedia_aud_param *param,
+					       pjmedia_aud_dev_cap cap,
+					       const void *pval);
+
+
+/**
+ * Get a capability field value from #pjmedia_aud_param structure. This
+ * function will return PJMEDIA_EAUD_INVCAP error if the flag for that
+ * capability is not set in the flags field in the structure.
+ *
+ * @param param		The structure.
+ * @param cap		The audio capability which value is to be retrieved.
+ * @param pval		Pointer to value. Please see the type of value to
+ *			be supplied in the pjmedia_aud_dev_cap documentation.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_param_get_cap(const pjmedia_aud_param *param,
+					       pjmedia_aud_dev_cap cap,
+					       void *pval);
+
+
+/**
+ * Refresh the list of sound devices installed in the system. This function
+ * will only refresh the list of audio device so all active audio streams will
+ * be unaffected. After refreshing the device list, application MUST make sure
+ * to update all index references to audio devices (i.e. all variables of type
+ * pjmedia_aud_dev_index) before calling any function that accepts audio device
+ * index as its parameter.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_dev_refresh(void);
+
+
+/**
+ * Get the number of sound devices installed in the system.
+ *
+ * @return		The number of sound devices installed in the system.
+ */
+PJ_DECL(unsigned) pjmedia_aud_dev_count(void);
+
+
+/**
+ * Get device information.
+ *
+ * @param id		The audio device ID.
+ * @param info		The device information which will be filled in by this
+ *			function once it returns successfully.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
+					      pjmedia_aud_dev_info *info);
+
+
+/**
+ * Lookup device index based on the driver and device name.
+ *
+ * @param drv_name	The driver name.
+ * @param dev_name	The device name.
+ * @param id		Pointer to store the returned device ID.
+ *
+ * @return		PJ_SUCCESS if the device can be found.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_dev_lookup(const char *drv_name,
+					    const char *dev_name,
+					    pjmedia_aud_dev_index *id);
+
+
+/**
+ * Initialize the audio device parameters with default values for the
+ * specified device.
+ *
+ * @param id		The audio device ID.
+ * @param param		The audio device parameters which will be initialized
+ *			by this function once it returns successfully.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
+						   pjmedia_aud_param *param);
+
+
+/**
+ * Open audio stream object using the specified parameters.
+ *
+ * @param param		Sound device parameters to be used for the stream.
+ * @param rec_cb	Callback to be called on every input frame captured.
+ * @param play_cb	Callback to be called everytime the sound device needs
+ *			audio frames to be played back.
+ * @param user_data	Arbitrary user data, which will be given back in the
+ *			callbacks.
+ * @param p_strm	Pointer to receive the audio stream.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *param,
+					       pjmedia_aud_rec_cb rec_cb,
+					       pjmedia_aud_play_cb play_cb,
+					       void *user_data,
+					       pjmedia_aud_stream **p_strm);
+
+/**
+ * Get the running parameters for the specified audio stream.
+ *
+ * @param strm		The audio stream.
+ * @param param		Audio stream parameters to be filled in by this 
+ *			function once it returns successfully.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
+						  pjmedia_aud_param *param);
+
+/**
+ * Get the value of a specific capability of the audio stream.
+ *
+ * @param strm		The audio stream.
+ * @param cap		The audio capability which value is to be retrieved.
+ * @param value		Pointer to value to be filled in by this function 
+ *			once it returns successfully.  Please see the type 
+ *			of value to be supplied in the pjmedia_aud_dev_cap
+ *			documentation.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
+						pjmedia_aud_dev_cap cap,
+						void *value);
+
+/**
+ * Set the value of a specific capability of the audio stream.
+ *
+ * @param strm		The audio stream.
+ * @param cap		The audio capability which value is to be set.
+ * @param value		Pointer to value. Please see the type of value to
+ *			be supplied in the pjmedia_aud_dev_cap documentation.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
+						pjmedia_aud_dev_cap cap,
+						const void *value);
+
+/**
+ * Start the stream.
+ *
+ * @param strm		The audio stream.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm);
+
+/**
+ * Stop the stream.
+ *
+ * @param strm		The audio stream.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm);
+
+/**
+ * Destroy the stream.
+ *
+ * @param strm		The audio stream.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif	/* __PJMEDIA_AUDIO_DEV_H__ */
+
Index: /pjproject/trunk/pjmedia/include/pjmedia/endpoint.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/endpoint.h	(revision 5254)
+++ /pjproject/trunk/pjmedia/include/pjmedia/endpoint.h	(revision 5255)
@@ -41,4 +41,5 @@
 #include <pjmedia/sdp.h>
 #include <pjmedia/transport.h>
+#include <pjmedia-audiodev/audiodev.h>
 
 
@@ -82,5 +83,5 @@
  * @return		PJ_SUCCESS on success.
  */
-PJ_DECL(pj_status_t) pjmedia_endpt_create( pj_pool_factory *pf,
+PJ_DECL(pj_status_t) pjmedia_endpt_create2(pj_pool_factory *pf,
 					   pj_ioqueue_t *ioqueue,
 					   unsigned worker_cnt,
@@ -88,4 +89,44 @@
 
 /**
+ * Create an instance of media endpoint and initialize audio subsystem.
+ *
+ * @param pf		Pool factory, which will be used by the media endpoint
+ *			throughout its lifetime.
+ * @param ioqueue	Optional ioqueue instance to be registered to the 
+ *			endpoint. The ioqueue instance is used to poll all RTP
+ *			and RTCP sockets. If this argument is NULL, the 
+ *			endpoint will create an internal ioqueue instance.
+ * @param worker_cnt	Specify the number of worker threads to be created
+ *			to poll the ioqueue.
+ * @param p_endpt	Pointer to receive the endpoint instance.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_INLINE(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
+					    pj_ioqueue_t *ioqueue,
+					    unsigned worker_cnt,
+					    pjmedia_endpt **p_endpt)
+{
+    /* This function is inlined to avoid build problem due to circular
+     * dependency, i.e: this function prevents pjmedia's dependency on
+     * pjmedia-audiodev.
+     */
+
+    pj_status_t status;
+
+    /* Sound */
+    status = pjmedia_aud_subsys_init(pf);
+    if (status != PJ_SUCCESS)
+        return status;
+
+    status = pjmedia_endpt_create2(pf, ioqueue, worker_cnt, p_endpt);
+    if (status != PJ_SUCCESS) {
+        pjmedia_aud_subsys_shutdown();
+    }
+    
+    return status;
+}
+
+/**
  * Destroy media endpoint instance.
  *
@@ -94,5 +135,23 @@
  * @return		PJ_SUCCESS on success.
  */
-PJ_DECL(pj_status_t) pjmedia_endpt_destroy(pjmedia_endpt *endpt);
+PJ_DECL(pj_status_t) pjmedia_endpt_destroy2(pjmedia_endpt *endpt);
+
+/**
+ * Destroy media endpoint instance and shutdown audio subsystem.
+ *
+ * @param endpt		Media endpoint instance.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_INLINE(pj_status_t) pjmedia_endpt_destroy(pjmedia_endpt *endpt)
+{
+    /* This function is inlined to avoid build problem due to circular
+     * dependency, i.e: this function prevents pjmedia's dependency on
+     * pjmedia-audiodev.
+     */
+     pj_status_t status = pjmedia_endpt_destroy2(endpt);
+     pjmedia_aud_subsys_shutdown();
+     return status;
+}
 
 /**
Index: /pjproject/trunk/pjmedia/include/pjmedia/sound.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sound.h	(revision 5254)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sound.h	(revision 5255)
@@ -141,6 +141,11 @@
  * @return		Zero on success.
  */
-PJ_DECL(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory);
-
+PJ_INLINE(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
+{
+    /* This function is inlined to avoid pjmedia's dependency on
+     * pjmedia-audiodev.
+     */
+    return pjmedia_aud_subsys_init(factory);
+}
 
 /**
@@ -324,5 +329,11 @@
  * @return		Zero on success.
  */
-PJ_DECL(pj_status_t) pjmedia_snd_deinit(void);
+PJ_INLINE(pj_status_t) pjmedia_snd_deinit(void)
+{
+    /* This function is inlined to avoid pjmedia's dependency on
+     * pjmedia-audiodev.
+     */
+    return pjmedia_aud_subsys_shutdown();
+}
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/videodev.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/videodev.h	(revision 5255)
+++ /pjproject/trunk/pjmedia/include/pjmedia/videodev.h	(revision 5255)
@@ -0,0 +1,824 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __PJMEDIA_VIDEO_DEV_H__
+#define __PJMEDIA_VIDEO_DEV_H__
+
+/**
+ * @file videodev.h
+ * @brief Video device API.
+ */
+#include <pjmedia-videodev/config.h>
+#include <pjmedia-videodev/errno.h>
+#include <pjmedia/event.h>
+#include <pjmedia/frame.h>
+#include <pjmedia/format.h>
+#include <pj/pool.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup video_device_reference Video Device API Reference
+ * @ingroup video_device_api
+ * @brief API Reference
+ * @{
+ */
+ 
+/**
+ * Type for device index.
+ */
+typedef pj_int32_t pjmedia_vid_dev_index;
+
+/**
+ * Enumeration of window handle type.
+ */
+typedef enum pjmedia_vid_dev_hwnd_type
+{
+    /**
+     * Type none.
+     */
+    PJMEDIA_VID_DEV_HWND_TYPE_NONE,
+
+    /**
+     * Native window handle on Windows.
+     */
+    PJMEDIA_VID_DEV_HWND_TYPE_WINDOWS,
+
+    /**
+     * Native view on iOS.
+     */
+    PJMEDIA_VID_DEV_HWND_TYPE_IOS,
+
+    /**
+     * Native window handle on Android.
+     */
+    PJMEDIA_VID_DEV_HWND_TYPE_ANDROID
+
+} pjmedia_vid_dev_hwnd_type;
+
+/**
+ * Type for window handle.
+ */
+typedef struct pjmedia_vid_dev_hwnd
+{
+    /**
+     * The window handle type.
+     */
+    pjmedia_vid_dev_hwnd_type type;
+
+    /**
+     * The window handle.
+     */
+    union
+    {
+	struct {
+	    void    *hwnd;	/**< HWND     	*/
+	} win;
+	struct {
+	    void    *window;    /**< Window	*/
+	    void    *display;   /**< Display	*/
+	} x11;
+	struct {
+	    void    *window;    /**< Window	*/
+	} cocoa;
+	struct {
+	    void    *window;    /**< Window	*/
+	} ios;
+	struct {
+	    void    *window;    /**< Native window */
+	} android;
+	void 	    *window;
+    } info;
+
+} pjmedia_vid_dev_hwnd;
+
+/**
+ * Parameter for switching device with PJMEDIA_VID_DEV_CAP_SWITCH capability.
+ * Initialize this with pjmedia_vid_dev_switch_param_default()
+ */
+typedef struct pjmedia_vid_dev_switch_param
+{
+    /**
+     * Target device ID to switch to. Once the switching is successful, the
+     * video stream will use this device and the old device will be closed.
+     */
+    pjmedia_vid_dev_index target_id;
+
+} pjmedia_vid_dev_switch_param;
+
+
+/**
+ * Enumeration of window flags.
+ */
+typedef enum pjmedia_vid_dev_wnd_flag
+{
+    /**
+     * Window with border.
+     */
+    PJMEDIA_VID_DEV_WND_BORDER = 1,
+
+    /**
+     * Window can be resized.
+     */
+    PJMEDIA_VID_DEV_WND_RESIZABLE = 2
+
+} pjmedia_vid_dev_wnd_flag;
+
+
+/**
+ * Device index constants.
+ */
+enum pjmedia_vid_dev_std_index
+{
+    /**
+     * Constant to denote default capture device
+     */
+    PJMEDIA_VID_DEFAULT_CAPTURE_DEV = -1,
+
+    /**
+     * Constant to denote default render device
+     */
+    PJMEDIA_VID_DEFAULT_RENDER_DEV = -2,
+
+    /**
+     * Constant to denote invalid device index.
+     */
+    PJMEDIA_VID_INVALID_DEV = -3
+};
+
+
+/**
+ * This enumeration identifies various video device capabilities. These video
+ * capabilities indicates what features are supported by the underlying
+ * video device implementation.
+ *
+ * Applications get these capabilities in the #pjmedia_vid_dev_info structure.
+ *
+ * Application can also set the specific features/capabilities when opening
+ * the video stream by setting the \a flags member of #pjmedia_vid_dev_param
+ * structure.
+ *
+ * Once video stream is running, application can also retrieve or set some
+ * specific video capability, by using #pjmedia_vid_dev_stream_get_cap() and
+ * #pjmedia_vid_dev_stream_set_cap() and specifying the desired capability. The
+ * value of the capability is specified as pointer, and application needs to
+ * supply the pointer with the correct value, according to the documentation
+ * of each of the capability.
+ */
+typedef enum pjmedia_vid_dev_cap
+{
+    /**
+     * Support for video formats. The value of this capability
+     * is represented by #pjmedia_format structure.
+     */
+    PJMEDIA_VID_DEV_CAP_FORMAT = 1,
+
+    /**
+     * Support for video input scaling
+     */
+    PJMEDIA_VID_DEV_CAP_INPUT_SCALE = 2,
+
+    /**
+     * Support for returning the native window handle of the video window.
+     * For renderer, this means the window handle of the renderer window,
+     * while for capture, this means the window handle of the native preview,
+     * only if the device supports  PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW
+     * capability.
+     *
+     * The value of this capability is pointer to pjmedia_vid_dev_hwnd
+     * structure.
+     */
+    PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW = 4,
+
+    /**
+     * Support for resizing video output. This capability SHOULD be 
+     * implemented by renderer, to alter the video output dimension on the fly.
+     * Value is pjmedia_rect_size. 
+     */
+    PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE = 8,
+
+    /**
+     * Support for setting the video window's position.
+     * Value is pjmedia_coord specifying the window's new coordinate.
+     */
+    PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION = 16,
+
+    /**
+     * Support for setting the video output's visibility.
+     * The value of this capability is a pj_bool_t containing boolean
+     * PJ_TRUE or PJ_FALSE.
+     */
+    PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE = 32,
+
+    /**
+     * Support for native preview capability in capture devices. Value is
+     * pj_bool_t. With native preview, capture device can be instructed to
+     * show or hide a preview window showing video directly from the camera
+     * by setting this capability to PJ_TRUE or PJ_FALSE. Once the preview
+     * is started, application may use PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW
+     * capability to query the video window.
+     *
+     * The value of this capability is a pj_bool_t containing boolean
+     * PJ_TRUE or PJ_FALSE.
+     */
+    PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW = 64,
+
+    /**
+     * Support for changing video orientation. For a renderer device,
+     * changing video orientation in will potentially affect the size of
+     * render window, i.e: width and height swap. For a capture device,
+     * the video will be rotated but the size of the video frame
+     * will stay the same, so the video may be resized or stretched.
+     *
+     * The value of this capability is pjmedia_orient.
+     */
+    PJMEDIA_VID_DEV_CAP_ORIENTATION = 128,
+
+    /**
+     * Support for fast switching to another device. A video stream with this
+     * capability allows replacing of its underlying device with another
+     * device, saving the user from opening a new video stream and gets a much
+     * faster and smoother switching action.
+     *
+     * Note that even when this capability is supported by a device, it may
+     * not be able to switch to arbitrary device. Application must always
+     * check the return value of the operation to verify that switching has
+     * occurred.
+     *
+     * This capability is currently write-only (i.e. set-only).
+     *
+     * The value of this capability is pointer to pjmedia_vid_dev_switch_param
+     * structure.
+     */
+    PJMEDIA_VID_DEV_CAP_SWITCH = 256,
+
+    /**
+     * Support for setting the output video window's flags.
+     * The value of this capability is a bitmask combination of
+     * #pjmedia_vid_dev_wnd_flag.
+     */
+    PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS = 512,
+
+    /**
+     * End of standard capability
+     */
+    PJMEDIA_VID_DEV_CAP_MAX = 16384
+
+} pjmedia_vid_dev_cap;
+
+/**
+ * Device information structure returned by #pjmedia_vid_dev_get_info().
+ */
+typedef struct pjmedia_vid_dev_info
+{
+    /** The device ID */
+    pjmedia_vid_dev_index id;
+
+    /** The device name */
+    char name[64];
+
+    /** The underlying driver name */
+    char driver[32];
+
+    /** 
+     * The supported direction of the video device, i.e. whether it supports 
+     * capture only, render only, or both.
+     */
+    pjmedia_dir dir;
+
+    /**
+     * Specify whether the device supports callback. Devices that implement
+     * "active interface" will actively call the callbacks to give or ask for
+     * video frames. If the device doesn't support callback, application
+     * must actively request or give video frames from/to the device by using
+     * pjmedia_vid_dev_stream_get_frame()/pjmedia_vid_dev_stream_put_frame().
+     */
+    pj_bool_t has_callback;
+
+    /** Device capabilities, as bitmask combination of #pjmedia_vid_dev_cap */
+    unsigned caps;
+
+    /** Number of video formats supported by this device */
+    unsigned fmt_cnt;
+
+    /** 
+     * Array of supported video formats. Some fields in each supported video
+     * format may be set to zero or of "unknown" value, to indicate that the
+     * value is unknown or should be ignored. When these value are not set
+     * to zero, it indicates that the exact format combination is being used. 
+     */
+    pjmedia_format fmt[PJMEDIA_VID_DEV_INFO_FMT_CNT];
+
+} pjmedia_vid_dev_info;
+
+
+/** Forward declaration for pjmedia_vid_dev_stream */
+typedef struct pjmedia_vid_dev_stream pjmedia_vid_dev_stream;
+
+typedef struct pjmedia_vid_dev_cb
+{
+    /**
+    * This callback is called by capturer stream when it has captured the
+    * whole packet worth of video samples.
+    *
+    * @param stream	   The video stream.
+    * @param user_data     User data associated with the stream.
+    * @param frame         Captured frame.
+    *
+    * @return              Returning non-PJ_SUCCESS will cause the video
+    *                      stream to stop
+    */
+    pj_status_t (*capture_cb)(pjmedia_vid_dev_stream *stream,
+		              void *user_data,
+                              pjmedia_frame *frame);
+
+    /**
+    * This callback is called by renderer stream when it needs additional
+    * data to be rendered by the device. Application must fill in the whole
+    * of output buffer with video samples.
+    *
+    * The frame argument contains the following values:
+    *  - timestamp         Rendering timestamp, in samples.
+    *  - buf               Buffer to be filled out by application.
+    *  - size              The size requested in bytes, which will be equal
+    *                      to the size of one whole packet.
+    *
+    * @param stream	   The video stream.
+    * @param user_data     User data associated with the stream.
+    * @param frame         Video frame, which buffer is to be filled in by
+    *                      the application.
+    *
+    * @return              Returning non-PJ_SUCCESS will cause the video 
+    *                      stream to stop
+    */
+    pj_status_t (*render_cb)(pjmedia_vid_dev_stream *stream,
+			     void *user_data,
+                             pjmedia_frame *frame);
+
+} pjmedia_vid_dev_cb;
+
+
+/**
+ * This structure specifies the parameters to open the video stream.
+ */
+typedef struct pjmedia_vid_dev_param
+{
+    /**
+     * The video direction. This setting is mandatory.
+     */
+    pjmedia_dir dir;
+
+    /**
+     * The video capture device ID. This setting is mandatory if the video
+     * direction includes input/capture direction.
+     */
+    pjmedia_vid_dev_index cap_id;
+
+    /**
+     * The video render device ID. This setting is mandatory if the video
+     * direction includes output/render direction.
+     */
+    pjmedia_vid_dev_index rend_id;
+
+    /** 
+     * Video clock rate. This setting is mandatory if the video
+     * direction includes input/capture direction
+     */
+    unsigned clock_rate;
+
+    /**
+     * Video frame rate. This setting is mandatory if the video
+     * direction includes input/capture direction
+     */
+//    pjmedia_ratio frame_rate;
+
+    /**
+     * This flags specifies which of the optional settings are valid in this
+     * structure. The flags is bitmask combination of pjmedia_vid_dev_cap.
+     */
+    unsigned flags;
+
+    /**
+     * Set the video format. This setting is mandatory.
+     */
+    pjmedia_format fmt;
+
+    /**
+     * Window for the renderer to display the video. This setting is optional,
+     * and will only be used if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW is set in 
+     * the flags.
+     */
+    pjmedia_vid_dev_hwnd window;
+
+    /**
+     * Video display size. This setting is optional, and will only be used 
+     * if PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE is set in the flags.
+     */
+    pjmedia_rect_size disp_size;
+
+    /**
+     * Video window position. This setting is optional, and will only be used
+     * if PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION is set in the flags.
+     */
+    pjmedia_coord window_pos;
+
+    /**
+     * Video window's visibility. This setting is optional, and will only be
+     * used if PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE is set in the flags.
+     */
+    pj_bool_t window_hide;
+
+    /**
+     * Enable built-in preview. This setting is optional and is only used
+     * if PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW capability is supported and
+     * set in the flags.
+     */
+    pj_bool_t native_preview;
+
+    /**
+     * Video orientation. This setting is optional and is only used if
+     * PJMEDIA_VID_DEV_CAP_ORIENTATION capability is supported and is
+     * set in the flags.
+     */
+    pjmedia_orient orient;
+
+    /**
+     * Video window flags. This setting is optional, and will only be used
+     * if PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS is set in the flags.
+     */
+    unsigned window_flags;
+
+} pjmedia_vid_dev_param;
+
+
+/** Forward declaration for video device factory */
+typedef struct pjmedia_vid_dev_factory pjmedia_vid_dev_factory;
+
+/* typedef for factory creation function */
+typedef pjmedia_vid_dev_factory*
+(*pjmedia_vid_dev_factory_create_func_ptr)(pj_pool_factory*);
+
+
+/* Video driver structure */
+typedef struct pjmedia_vid_driver
+{
+    pjmedia_vid_dev_factory_create_func_ptr create; /* Creation function    */
+    pjmedia_vid_dev_factory *f;    	    /* Factory instance		    */
+    char		     name[32];	    /* Driver name		    */
+    unsigned		     dev_cnt;	    /* Number of devices	    */
+    unsigned		     start_idx;	    /* Start index in global list   */
+    int			     cap_dev_idx;   /* Default capture device.	    */
+    int			     rend_dev_idx;  /* Default render device	    */
+} pjmedia_vid_driver;
+
+
+/* The video device subsystem */
+typedef struct pjmedia_vid_subsys
+{
+    unsigned	     	init_count;	/* How many times init() is called   */
+    pj_pool_factory    *pf;		/* The pool factory.		     */
+
+    unsigned	     	drv_cnt;	/* Number of drivers.		     */
+    pjmedia_vid_driver 	drv[PJMEDIA_VID_DEV_MAX_DRIVERS];/* Array of drivers.*/
+
+    unsigned	     	dev_cnt;	/* Total number of devices.	     */
+    pj_uint32_t	     	dev_list[PJMEDIA_VID_DEV_MAX_DEVS];/* Array of devIDs*/
+
+} pjmedia_vid_subsys;
+
+
+/**
+ * Get the video subsystem.
+ *
+ * @return		The video subsystem.
+ */
+PJ_DECL(pjmedia_vid_subsys*) pjmedia_get_vid_subsys(void);
+
+
+/**
+ * Initialize the video driver.
+ *
+ * @param drv_idx	The index of the video driver.
+ * @param refresh	Specify non-zero to refresh the video driver.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_driver_init(unsigned drv_idx,
+					     pj_bool_t refresh);
+
+
+/**
+ * Deinitialize the video driver.
+ *
+ * @param drv_idx	The index of the video driver.
+ */
+PJ_DECL(void) pjmedia_vid_driver_deinit(unsigned drv_idx);
+
+
+/**
+ * Initialize pjmedia_vid_dev_switch_param.
+ *
+ * @param p	    Parameter to be initialized.
+ */
+PJ_INLINE(void)
+pjmedia_vid_dev_switch_param_default(pjmedia_vid_dev_switch_param *p)
+{
+    pj_bzero(p, sizeof(*p));
+    p->target_id = PJMEDIA_VID_INVALID_DEV;
+}
+
+/**
+ * Get string info for the specified capability.
+ *
+ * @param cap       The capability ID.
+ * @param p_desc    Optional pointer which will be filled with longer
+ *                  description about the capability.
+ *
+ * @return          Capability name.
+ */
+PJ_DECL(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
+                                              const char **p_desc);
+
+
+/**
+ * Set a capability field value in #pjmedia_vid_dev_param structure. This will
+ * also set the flags field for the specified capability in the structure.
+ *
+ * @param param     The structure.
+ * @param cap       The video capability which value is to be set.
+ * @param pval      Pointer to value. Please see the type of value to
+ *                  be supplied in the pjmedia_vid_dev_cap documentation.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_vid_dev_param_set_cap(pjmedia_vid_dev_param *param,
+                              pjmedia_vid_dev_cap cap,
+                              const void *pval);
+
+
+/**
+ * Get a capability field value from #pjmedia_vid_dev_param structure. This
+ * function will return PJMEDIA_EVID_INVCAP error if the flag for that
+ * capability is not set in the flags field in the structure.
+ *
+ * @param param     The structure.
+ * @param cap       The video capability which value is to be retrieved.
+ * @param pval      Pointer to value. Please see the type of value to
+ *                  be supplied in the pjmedia_vid_dev_cap documentation.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_vid_dev_param_get_cap(const pjmedia_vid_dev_param *param,
+                              pjmedia_vid_dev_cap cap,
+                              void *pval);
+
+
+/**
+ * Refresh the list of video devices installed in the system. This function
+ * will only refresh the list of videoo device so all active video streams will
+ * be unaffected. After refreshing the device list, application MUST make sure
+ * to update all index references to video devices (i.e. all variables of type
+ * pjmedia_vid_dev_index) before calling any function that accepts video device
+ * index as its parameter.
+ *
+ * @return		PJ_SUCCESS on successful operation or the appropriate
+ *			error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_refresh(void);
+
+
+/**
+ * Get the number of video devices installed in the system.
+ *
+ * @return          The number of video devices installed in the system.
+ */
+PJ_DECL(unsigned) pjmedia_vid_dev_count(void);
+
+
+/**
+ * Get device information.
+ *
+ * @param id        The video device ID.
+ * @param info      The device information which will be filled in by this
+ *                  function once it returns successfully.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
+                                              pjmedia_vid_dev_info *info);
+
+
+/**
+ * Lookup device index based on the driver and device name.
+ *
+ * @param drv_name  The driver name.
+ * @param dev_name  The device name.
+ * @param id        Pointer to store the returned device ID.
+ *
+ * @return          PJ_SUCCESS if the device can be found.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_lookup(const char *drv_name,
+                                            const char *dev_name,
+                                            pjmedia_vid_dev_index *id);
+
+
+/**
+ * Initialize the video device parameters with default values for the
+ * specified device.
+ *
+ * @param id        The video device ID.
+ * @param param     The video device parameters which will be initialized
+ *                  by this function once it returns successfully.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_vid_dev_default_param(pj_pool_t *pool,
+                              pjmedia_vid_dev_index id,
+                              pjmedia_vid_dev_param *param);
+
+
+/**
+ * Open video stream object using the specified parameters. If stream is
+ * created successfully, this function will return PJ_SUCCESS and the
+ * stream pointer will be returned in the p_strm argument.
+ *
+ * The opened stream may have been opened with different size and fps
+ * than the requested values in the \a param argument. Application should
+ * check the actual size and fps that the stream was opened with by inspecting
+ * the values in the \a param argument and see if they have changed. Also
+ * if the device ID in the \a param specifies default device, it may be
+ * replaced with the actual device ID upon return.
+ *
+ * @param param         On input, it specifies the video device parameters
+ *                      to be used for the stream. On output, this will be
+ *                      set to the actual video device parameters used to
+ *                      open the stream.
+ * @param cb            Pointer to structure containing video stream
+ *                      callbacks.
+ * @param user_data     Arbitrary user data, which will be given back in the
+ *                      callbacks.
+ * @param p_strm        Pointer to receive the video stream.
+ *
+ * @return              PJ_SUCCESS on successful operation or the appropriate
+ *                      error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_create(
+					    pjmedia_vid_dev_param *param,
+					    const pjmedia_vid_dev_cb *cb,
+					    void *user_data,
+					    pjmedia_vid_dev_stream **p_strm);
+
+/**
+ * Get the running parameters for the specified video stream.
+ *
+ * @param strm      The video stream.
+ * @param param     Video stream parameters to be filled in by this
+ *                  function once it returns successfully.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_param(
+					    pjmedia_vid_dev_stream *strm,
+                                            pjmedia_vid_dev_param *param);
+
+/**
+ * Get the value of a specific capability of the video stream.
+ *
+ * @param strm      The video stream.
+ * @param cap       The video capability which value is to be retrieved.
+ * @param value     Pointer to value to be filled in by this function
+ *                  once it returns successfully.  Please see the type
+ *                  of value to be supplied in the pjmedia_vid_dev_cap
+ *                  documentation.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_cap(
+					    pjmedia_vid_dev_stream *strm,
+					    pjmedia_vid_dev_cap cap,
+                                            void *value);
+
+/**
+ * Set the value of a specific capability of the video stream.
+ *
+ * @param strm      The video stream.
+ * @param cap       The video capability which value is to be set.
+ * @param value     Pointer to value. Please see the type of value to
+ *                  be supplied in the pjmedia_vid_dev_cap documentation.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_set_cap(
+					    pjmedia_vid_dev_stream *strm,
+					    pjmedia_vid_dev_cap cap,
+					    const void *value);
+
+/**
+ * Start the stream.
+ *
+ * @param strm      The video stream.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_start(
+					    pjmedia_vid_dev_stream *strm);
+
+/**
+ * Query whether the stream has been started.
+ *
+ * @param strm	    The video stream
+ *
+ * @return	    PJ_TRUE if the video stream has been started.
+ */
+PJ_DECL(pj_bool_t) pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm);
+
+
+/**
+ * Request one frame from the stream. Application needs to call this function
+ * periodically only if the stream doesn't support "active interface", i.e.
+ * the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
+ *
+ * @param strm      The video stream.
+ * @param frame	    The video frame to be filled by the device.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_get_frame(
+					    pjmedia_vid_dev_stream *strm,
+                                            pjmedia_frame *frame);
+
+/**
+ * Put one frame to the stream. Application needs to call this function
+ * periodically only if the stream doesn't support "active interface", i.e.
+ * the pjmedia_vid_dev_info.has_callback member is PJ_FALSE.
+ *
+ * @param strm      The video stream.
+ * @param frame	    The video frame to put to the device.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_put_frame(
+					    pjmedia_vid_dev_stream *strm,
+                                            const pjmedia_frame *frame);
+
+/**
+ * Stop the stream.
+ *
+ * @param strm      The video stream.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_stop(
+					    pjmedia_vid_dev_stream *strm);
+
+/**
+ * Destroy the stream.
+ *
+ * @param strm      The video stream.
+ *
+ * @return          PJ_SUCCESS on successful operation or the appropriate
+ *                  error code.
+ */
+PJ_DECL(pj_status_t) pjmedia_vid_dev_stream_destroy(
+					    pjmedia_vid_dev_stream *strm);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif    /* __PJMEDIA_VIDEO_DEV_H__ */
Index: /pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 5254)
+++ /pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 5255)
@@ -20,48 +20,6 @@
 #include <pjmedia-audiodev/audiodev_imp.h>
 #include <pj/assert.h>
-#include <pj/errno.h>
-#include <pj/log.h>
-#include <pj/pool.h>
-#include <pj/string.h>
 
 #define THIS_FILE   "audiodev.c"
-
-#define DEFINE_CAP(name, info)	{name, info}
-
-/* Capability names */
-static struct cap_info
-{
-    const char *name;
-    const char *info;
-} cap_infos[] = 
-{
-    DEFINE_CAP("ext-fmt",     "Extended/non-PCM format"),
-    DEFINE_CAP("latency-in",  "Input latency/buffer size setting"),
-    DEFINE_CAP("latency-out", "Output latency/buffer size setting"),
-    DEFINE_CAP("vol-in",      "Input volume setting"),
-    DEFINE_CAP("vol-out",     "Output volume setting"),
-    DEFINE_CAP("meter-in",    "Input meter"),
-    DEFINE_CAP("meter-out",   "Output meter"),
-    DEFINE_CAP("route-in",    "Input routing"),
-    DEFINE_CAP("route-out",   "Output routing"),
-    DEFINE_CAP("aec",	      "Accoustic echo cancellation"),
-    DEFINE_CAP("aec-tail",    "Tail length setting for AEC"),
-    DEFINE_CAP("vad",	      "Voice activity detection"),
-    DEFINE_CAP("cng",	      "Comfort noise generation"),
-    DEFINE_CAP("plg",	      "Packet loss concealment")
-};
-
-
-/*
- * The device index seen by application and driver is different. 
- *
- * At application level, device index is index to global list of device.
- * At driver level, device index is index to device list on that particular
- * factory only.
- */
-#define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
-#define GET_INDEX(dev_id)	   ((dev_id) & 0xFFFF)
-#define GET_FID(dev_id)		   ((dev_id) >> 16)
-#define DEFAULT_DEV_ID		    0
 
 
@@ -115,272 +73,4 @@
 #endif
 
-#define MAX_DRIVERS	16
-#define MAX_DEVS	64
-
-
-/* driver structure */
-struct driver
-{
-    /* Creation function */
-    pjmedia_aud_dev_factory_create_func_ptr create;
-    /* Factory instance */
-    pjmedia_aud_dev_factory *f;
-    char		     name[32];	/* Driver name			    */
-    unsigned		     dev_cnt;	/* Number of devices		    */
-    unsigned		     start_idx;	/* Start index in global list	    */
-    int			     rec_dev_idx;/* Default capture device.	    */
-    int			     play_dev_idx;/* Default playback device	    */
-    int			     dev_idx;	/* Default device.		    */
-};
-
-/* The audio subsystem */
-static struct aud_subsys
-{
-    unsigned	     init_count;	/* How many times init() is called  */
-    pj_pool_factory *pf;		/* The pool factory.		    */
-
-    unsigned	     drv_cnt;		/* Number of drivers.		    */
-    struct driver    drv[MAX_DRIVERS];	/* Array of drivers.		    */
-
-    unsigned	     dev_cnt;		/* Total number of devices.	    */
-    pj_uint32_t	     dev_list[MAX_DEVS];/* Array of device IDs.		    */
-
-} aud_subsys;
-
-/* API: get capability name/info */
-PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
-					     const char **p_desc)
-{
-    const char *desc;
-    unsigned i;
-
-    if (p_desc==NULL) p_desc = &desc;
-
-    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
-	if ((1 << i)==cap)
-	    break;
-    }
-
-    if (i==PJ_ARRAY_SIZE(cap_infos)) {
-	*p_desc = "??";
-	return "??";
-    }
-
-    *p_desc = cap_infos[i].info;
-    return cap_infos[i].name;
-}
-
-static pj_status_t get_cap_pointer(const pjmedia_aud_param *param,
-				   pjmedia_aud_dev_cap cap,
-				   void **ptr,
-				   unsigned *size)
-{
-#define FIELD_INFO(name)    *ptr = (void*)&param->name; \
-			    *size = sizeof(param->name)
-
-    switch (cap) {
-    case PJMEDIA_AUD_DEV_CAP_EXT_FORMAT:
-	FIELD_INFO(ext_fmt);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY:
-	FIELD_INFO(input_latency_ms);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY:
-	FIELD_INFO(output_latency_ms);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
-	FIELD_INFO(input_vol);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
-	FIELD_INFO(output_vol);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE:
-	FIELD_INFO(input_route);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
-	FIELD_INFO(output_route);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_EC:
-	FIELD_INFO(ec_enabled);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_EC_TAIL:
-	FIELD_INFO(ec_tail_ms);
-	break;
-    /* vad is no longer in "fmt" in 2.0.
-    case PJMEDIA_AUD_DEV_CAP_VAD:
-	FIELD_INFO(ext_fmt.vad);
-	break;
-    */
-    case PJMEDIA_AUD_DEV_CAP_CNG:
-	FIELD_INFO(cng_enabled);
-	break;
-    case PJMEDIA_AUD_DEV_CAP_PLC:
-	FIELD_INFO(plc_enabled);
-	break;
-    default:
-	return PJMEDIA_EAUD_INVCAP;
-    }
-
-#undef FIELD_INFO
-
-    return PJ_SUCCESS;
-}
-
-/* API: set cap value to param */
-PJ_DEF(pj_status_t) pjmedia_aud_param_set_cap( pjmedia_aud_param *param,
-					       pjmedia_aud_dev_cap cap,
-					       const void *pval)
-{
-    void *cap_ptr;
-    unsigned cap_size;
-    pj_status_t status;
-
-    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    pj_memcpy(cap_ptr, pval, cap_size);
-    param->flags |= cap;
-
-    return PJ_SUCCESS;
-}
-
-/* API: get cap value from param */
-PJ_DEF(pj_status_t) pjmedia_aud_param_get_cap( const pjmedia_aud_param *param,
-					       pjmedia_aud_dev_cap cap,
-					       void *pval)
-{
-    void *cap_ptr;
-    unsigned cap_size;
-    pj_status_t status;
-
-    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    if ((param->flags & cap) == 0) {
-	pj_bzero(cap_ptr, cap_size);
-	return PJMEDIA_EAUD_INVCAP;
-    }
-
-    pj_memcpy(pval, cap_ptr, cap_size);
-    return PJ_SUCCESS;
-}
-
-/* Internal: init driver */
-static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
-{
-    struct driver *drv = &aud_subsys.drv[drv_idx];
-    pjmedia_aud_dev_factory *f;
-    unsigned i, dev_cnt;
-    pj_status_t status;
-
-    if (!refresh && drv->create) {
-	/* Create the factory */
-	f = (*drv->create)(aud_subsys.pf);
-	if (!f)
-	    return PJ_EUNKNOWN;
-
-	/* Call factory->init() */
-	status = f->op->init(f);
-	if (status != PJ_SUCCESS) {
-	    f->op->destroy(f);
-	    return status;
-	}
-    } else {
-	f = drv->f;
-    }
-
-    if (!f)
-	return PJ_EUNKNOWN;
-
-    /* Get number of devices */
-    dev_cnt = f->op->get_dev_count(f);
-    if (dev_cnt + aud_subsys.dev_cnt > MAX_DEVS) {
-	PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
-			      " there are too many devices",
-			      aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));
-	dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;
-    }
-
-    /* enabling this will cause pjsua-lib initialization to fail when there
-     * is no sound device installed in the system, even when pjsua has been
-     * run with --null-audio
-     *
-    if (dev_cnt == 0) {
-	f->op->destroy(f);
-	return PJMEDIA_EAUD_NODEV;
-    }
-    */
-
-    /* Fill in default devices */
-    drv->play_dev_idx = drv->rec_dev_idx =
-			drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;
-    for (i=0; i<dev_cnt; ++i) {
-	pjmedia_aud_dev_info info;
-
-	status = f->op->get_dev_info(f, i, &info);
-	if (status != PJ_SUCCESS) {
-	    f->op->destroy(f);
-	    return status;
-	}
-
-	if (drv->name[0]=='\0') {
-	    /* Set driver name */
-	    pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
-	    drv->name[sizeof(drv->name)-1] = '\0';
-	}
-
-	if (drv->play_dev_idx < 0 && info.output_count) {
-	    /* Set default playback device */
-	    drv->play_dev_idx = i;
-	}
-	if (drv->rec_dev_idx < 0 && info.input_count) {
-	    /* Set default capture device */
-	    drv->rec_dev_idx = i;
-	}
-	if (drv->dev_idx < 0 && info.input_count &&
-	    info.output_count)
-	{
-	    /* Set default capture and playback device */
-	    drv->dev_idx = i;
-	}
-
-	if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 && 
-	    drv->dev_idx >= 0) 
-	{
-	    /* Done. */
-	    break;
-	}
-    }
-
-    /* Register the factory */
-    drv->f = f;
-    drv->f->sys.drv_idx = drv_idx;
-    drv->start_idx = aud_subsys.dev_cnt;
-    drv->dev_cnt = dev_cnt;
-
-    /* Register devices to global list */
-    for (i=0; i<dev_cnt; ++i) {
-	aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
-    }
-
-    return PJ_SUCCESS;
-}
-
-/* Internal: deinit driver */
-static void deinit_driver(unsigned drv_idx)
-{
-    struct driver *drv = &aud_subsys.drv[drv_idx];
-
-    if (drv->f) {
-	drv->f->op->destroy(drv->f);
-	drv->f = NULL;
-    }
-
-    pj_bzero(drv, sizeof(*drv));
-    drv->play_dev_idx = drv->rec_dev_idx = 
-			drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;
-}
 
 /* API: Initialize the audio subsystem. */
@@ -389,9 +79,10 @@
     unsigned i;
     pj_status_t status;
+    pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
 
     /* Allow init() to be called multiple times as long as there is matching
      * number of shutdown().
      */
-    if (aud_subsys.init_count++ != 0) {
+    if (aud_subsys->init_count++ != 0) {
 	return PJ_SUCCESS;
     }
@@ -404,56 +95,56 @@
 
     /* Init */
-    aud_subsys.pf = pf;
-    aud_subsys.drv_cnt = 0;
-    aud_subsys.dev_cnt = 0;
+    aud_subsys->pf = pf;
+    aud_subsys->drv_cnt = 0;
+    aud_subsys->dev_cnt = 0;
 
     /* Register creation functions */
 #if PJMEDIA_AUDIO_DEV_HAS_OPENSL
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_opensl_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_opensl_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_ANDROID_JNI
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_android_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_android_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_BB10
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bb10_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_bb10_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_ALSA
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_alsa_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_alsa_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_coreaudio_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_coreaudio_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_pa_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_WMME
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_wmme_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_BDIMAD
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bdimad_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_bdimad_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_vas_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_symb_vas_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_APS
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_aps_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_aps_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_symb_mda_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_symb_mda_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
-    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_null_audio_factory;
+    aud_subsys->drv[aud_subsys->drv_cnt++].create = &pjmedia_null_audio_factory;
 #endif
 
     /* Initialize each factory and build the device ID list */
-    for (i=0; i<aud_subsys.drv_cnt; ++i) {
-	status = init_driver(i, PJ_FALSE);
+    for (i=0; i<aud_subsys->drv_cnt; ++i) {
+	status = pjmedia_aud_driver_init(i, PJ_FALSE);
 	if (status != PJ_SUCCESS) {
-	    deinit_driver(i);
+	    pjmedia_aud_driver_deinit(i);
 	    continue;
 	}
     }
 
-    return aud_subsys.dev_cnt ? PJ_SUCCESS : status;
+    return aud_subsys->dev_cnt ? PJ_SUCCESS : status;
 }
 
@@ -463,14 +154,15 @@
 {
     pj_status_t status;
-
-    if (aud_subsys.init_count == 0)
+    pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
+
+    if (aud_subsys->init_count == 0)
 	return PJMEDIA_EAUD_INIT;
 
-    aud_subsys.drv[aud_subsys.drv_cnt].create = adf;
-    status = init_driver(aud_subsys.drv_cnt, PJ_FALSE);
+    aud_subsys->drv[aud_subsys->drv_cnt].create = adf;
+    status = pjmedia_aud_driver_init(aud_subsys->drv_cnt, PJ_FALSE);
     if (status == PJ_SUCCESS) {
-	aud_subsys.drv_cnt++;
+	aud_subsys->drv_cnt++;
     } else {
-	deinit_driver(aud_subsys.drv_cnt);
+	pjmedia_aud_driver_deinit(aud_subsys->drv_cnt);
     }
 
@@ -483,18 +175,19 @@
 {
     unsigned i, j;
-
-    if (aud_subsys.init_count == 0)
+    pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
+
+    if (aud_subsys->init_count == 0)
 	return PJMEDIA_EAUD_INIT;
 
-    for (i=0; i<aud_subsys.drv_cnt; ++i) {
-	struct driver *drv = &aud_subsys.drv[i];
+    for (i=0; i<aud_subsys->drv_cnt; ++i) {
+	pjmedia_aud_driver *drv = &aud_subsys->drv[i];
 
 	if (drv->create == adf) {
 	    for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
 	    {
-		aud_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;
+		aud_subsys->dev_list[j] = (pj_uint32_t)PJMEDIA_AUD_INVALID_DEV;
 	    }
 
-	    deinit_driver(i);
+	    pjmedia_aud_driver_deinit(i);
 	    return PJ_SUCCESS;
 	}
@@ -507,5 +200,6 @@
 PJ_DEF(pj_pool_factory*) pjmedia_aud_subsys_get_pool_factory(void)
 {
-    return aud_subsys.pf;
+    pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
+    return aud_subsys->pf;
 }
 
@@ -514,334 +208,21 @@
 {
     unsigned i;
+    pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys();
 
     /* Allow shutdown() to be called multiple times as long as there is matching
      * number of init().
      */
-    if (aud_subsys.init_count == 0) {
+    if (aud_subsys->init_count == 0) {
 	return PJ_SUCCESS;
     }
-    --aud_subsys.init_count;
-
-    if (aud_subsys.init_count == 0) {
-	for (i=0; i<aud_subsys.drv_cnt; ++i) {
-	    deinit_driver(i);
+    --aud_subsys->init_count;
+
+    if (aud_subsys->init_count == 0) {
+	for (i=0; i<aud_subsys->drv_cnt; ++i) {
+	    pjmedia_aud_driver_deinit(i);
 	}
 
-	aud_subsys.pf = NULL;
+	aud_subsys->pf = NULL;
     }
     return PJ_SUCCESS;
 }
-
-/* API: Refresh the list of sound devices installed in the system. */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void)
-{
-    unsigned i;
-    
-    aud_subsys.dev_cnt = 0;
-    for (i=0; i<aud_subsys.drv_cnt; ++i) {
-	struct driver *drv = &aud_subsys.drv[i];
-	
-	if (drv->f && drv->f->op->refresh) {
-	    pj_status_t status = drv->f->op->refresh(drv->f);
-	    if (status != PJ_SUCCESS) {
-		PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
-						 "list for %s", drv->name));
-	    }
-	}
-	init_driver(i, PJ_TRUE);
-    }
-    return PJ_SUCCESS;
-}
-
-/* API: Get the number of sound devices installed in the system. */
-PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
-{
-    return aud_subsys.dev_cnt;
-}
-
-/* Internal: convert local index to global device index */
-static pj_status_t make_global_index(unsigned drv_idx, 
-				     pjmedia_aud_dev_index *id)
-{
-    if (*id < 0) {
-	return PJ_SUCCESS;
-    }
-
-    /* Check that factory still exists */
-    PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);
-
-    /* Check that device index is valid */
-    PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt, 
-		     PJ_EBUG);
-
-    *id += aud_subsys.drv[drv_idx].start_idx;
-    return PJ_SUCCESS;
-}
-
-/* Internal: lookup device id */
-static pj_status_t lookup_dev(pjmedia_aud_dev_index id,
-			      pjmedia_aud_dev_factory **p_f,
-			      unsigned *p_local_index)
-{
-    int f_id, index;
-
-    if (id < 0) {
-	unsigned i;
-
-	if (id == PJMEDIA_AUD_INVALID_DEV)
-	    return PJMEDIA_EAUD_INVDEV;
-
-	for (i=0; i<aud_subsys.drv_cnt; ++i) {
-	    struct driver *drv = &aud_subsys.drv[i];
-	    if (drv->dev_idx >= 0) {
-		id = drv->dev_idx;
-		make_global_index(i, &id);
-		break;
-	    } else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV && 
-		drv->rec_dev_idx >= 0) 
-	    {
-		id = drv->rec_dev_idx;
-		make_global_index(i, &id);
-		break;
-	    } else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV && 
-		drv->play_dev_idx >= 0) 
-	    {
-		id = drv->play_dev_idx;
-		make_global_index(i, &id);
-		break;
-	    }
-	}
-
-	if (id < 0) {
-	    return PJMEDIA_EAUD_NODEFDEV;
-	}
-    }
-
-    f_id = GET_FID(aud_subsys.dev_list[id]);
-    index = GET_INDEX(aud_subsys.dev_list[id]);
-
-    if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
-	return PJMEDIA_EAUD_INVDEV;
-
-    if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
-	return PJMEDIA_EAUD_INVDEV;
-
-    *p_f = aud_subsys.drv[f_id].f;
-    *p_local_index = (unsigned)index;
-
-    return PJ_SUCCESS;
-
-}
-
-/* API: Get device information. */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
-					     pjmedia_aud_dev_info *info)
-{
-    pjmedia_aud_dev_factory *f;
-    unsigned index;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
-    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
-
-    status = lookup_dev(id, &f, &index);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    return f->op->get_dev_info(f, index, info);
-}
-
-/* API: find device */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,
-					    const char *dev_name,
-					    pjmedia_aud_dev_index *id)
-{
-    pjmedia_aud_dev_factory *f = NULL;
-    unsigned drv_idx, dev_idx;
-
-    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
-    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
-
-    for (drv_idx=0; drv_idx<aud_subsys.drv_cnt; ++drv_idx) {
-	if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[drv_idx].name)) {
-	    f = aud_subsys.drv[drv_idx].f;
-	    break;
-	}
-    }
-
-    if (!f)
-	return PJ_ENOTFOUND;
-
-    for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {
-	pjmedia_aud_dev_info info;
-	pj_status_t status;
-
-	status = f->op->get_dev_info(f, dev_idx, &info);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	if (!pj_ansi_stricmp(dev_name, info.name))
-	    break;
-    }
-
-    if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)
-	return PJ_ENOTFOUND;
-
-    *id = dev_idx;
-    make_global_index(drv_idx, id);
-
-    return PJ_SUCCESS;
-}
-
-/* API: Initialize the audio device parameters with default values for the
- * specified device.
- */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
-						  pjmedia_aud_param *param)
-{
-    pjmedia_aud_dev_factory *f;
-    unsigned index;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
-    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
-
-    status = lookup_dev(id, &f, &index);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    status = f->op->default_param(f, index, param);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Normalize device IDs */
-    make_global_index(f->sys.drv_idx, &param->rec_id);
-    make_global_index(f->sys.drv_idx, &param->play_id);
-
-    return PJ_SUCCESS;
-}
-
-/* API: Open audio stream object using the specified parameters. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,
-					      pjmedia_aud_rec_cb rec_cb,
-					      pjmedia_aud_play_cb play_cb,
-					      void *user_data,
-					      pjmedia_aud_stream **p_aud_strm)
-{
-    pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
-    pjmedia_aud_param param;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);
-    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
-    PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
-		     prm->dir==PJMEDIA_DIR_PLAYBACK ||
-		     prm->dir==PJMEDIA_DIR_CAPTURE_PLAYBACK,
-		     PJ_EINVAL);
-
-    /* Must make copy of param because we're changing device ID */
-    pj_memcpy(&param, prm, sizeof(param));
-
-    /* Normalize rec_id */
-    if (param.dir & PJMEDIA_DIR_CAPTURE) {
-	unsigned index;
-
-	if (param.rec_id < 0)
-	    param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
-
-	status = lookup_dev(param.rec_id, &rec_f, &index);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	param.rec_id = index;
-	f = rec_f;
-    }
-
-    /* Normalize play_id */
-    if (param.dir & PJMEDIA_DIR_PLAYBACK) {
-	unsigned index;
-
-	if (param.play_id < 0)
-	    param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
-
-	status = lookup_dev(param.play_id, &play_f, &index);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	param.play_id = index;
-	f = play_f;
-    }
-
-    PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
-
-    /* For now, rec_id and play_id must belong to the same factory */
-    PJ_ASSERT_RETURN((param.dir != PJMEDIA_DIR_CAPTURE_PLAYBACK) || 
-		     (rec_f == play_f),
-		     PJMEDIA_EAUD_INVDEV);
-
-    /* Create the stream */
-    status = f->op->create_stream(f, &param, rec_cb, play_cb,
-				  user_data, p_aud_strm);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Assign factory id to the stream */
-    (*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;
-    return PJ_SUCCESS;
-}
-
-/* API: Get the running parameters for the specified audio stream. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
-						 pjmedia_aud_param *param)
-{
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
-    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
-
-    status = strm->op->get_param(strm, param);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Normalize device id's */
-    make_global_index(strm->sys.drv_idx, &param->rec_id);
-    make_global_index(strm->sys.drv_idx, &param->play_id);
-
-    return PJ_SUCCESS;
-}
-
-/* API: Get the value of a specific capability of the audio stream. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
-					       pjmedia_aud_dev_cap cap,
-					       void *value)
-{
-    return strm->op->get_cap(strm, cap, value);
-}
-
-/* API: Set the value of a specific capability of the audio stream. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
-					       pjmedia_aud_dev_cap cap,
-					       const void *value)
-{
-    return strm->op->set_cap(strm, cap, value);
-}
-
-/* API: Start the stream. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
-{
-    return strm->op->start(strm);
-}
-
-/* API: Stop the stream. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
-{
-    return strm->op->stop(strm);
-}
-
-/* API: Destroy the stream. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
-{
-    return strm->op->destroy(strm);
-}
-
-
Index: /pjproject/trunk/pjmedia/src/pjmedia-videodev/videodev.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-videodev/videodev.c	(revision 5254)
+++ /pjproject/trunk/pjmedia/src/pjmedia-videodev/videodev.c	(revision 5255)
@@ -19,8 +19,4 @@
 #include <pjmedia-videodev/videodev_imp.h>
 #include <pj/assert.h>
-#include <pj/errno.h>
-#include <pj/log.h>
-#include <pj/pool.h>
-#include <pj/string.h>
 
 
@@ -29,38 +25,4 @@
 
 #define THIS_FILE   "videodev.c"
-
-#define DEFINE_CAP(name, info)	{name, info}
-
-/* Capability names */
-static struct cap_info
-{
-    const char *name;
-    const char *info;
-} cap_infos[] = 
-{
-    DEFINE_CAP("format",        "Video format"),
-    DEFINE_CAP("scale",         "Input dimension"),
-    DEFINE_CAP("window",        "Window handle"),
-    DEFINE_CAP("resize",        "Renderer resize"),
-    DEFINE_CAP("position",      "Renderer position"),
-    DEFINE_CAP("hide",          "Renderer hide"),
-    DEFINE_CAP("preview",       "Input preview"),
-    DEFINE_CAP("orientation",   "Video orientation"),
-    DEFINE_CAP("switch",        "Switch device"),
-    DEFINE_CAP("wndflags",      "Window flags")
-};
-
-
-/*
- * The device index seen by application and driver is different. 
- *
- * At application level, device index is index to global list of device.
- * At driver level, device index is index to device list on that particular
- * factory only.
- */
-#define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
-#define GET_INDEX(dev_id)	   ((dev_id) & 0xFFFF)
-#define GET_FID(dev_id)		   ((dev_id) >> 16)
-#define DEFAULT_DEV_ID		    0
 
 
@@ -110,250 +72,4 @@
 
 
-/* driver structure */
-struct driver
-{
-    /* Creation function */
-    pjmedia_vid_dev_factory_create_func_ptr create;
-    /* Factory instance */
-    pjmedia_vid_dev_factory *f;
-    char		     name[32];	    /* Driver name		    */
-    unsigned		     dev_cnt;	    /* Number of devices	    */
-    unsigned		     start_idx;	    /* Start index in global list   */
-    int			     cap_dev_idx;   /* Default capture device.	    */
-    int			     rend_dev_idx;  /* Default render device	    */
-};
-
-/* The video device subsystem */
-static struct vid_subsys
-{
-    unsigned	     init_count;	/* How many times init() is called  */
-    pj_pool_factory *pf;		/* The pool factory.		    */
-
-    unsigned	     drv_cnt;		/* Number of drivers.		    */
-    struct driver    drv[MAX_DRIVERS];	/* Array of drivers.		    */
-
-    unsigned	     dev_cnt;		/* Total number of devices.	    */
-    pj_uint32_t	     dev_list[MAX_DEVS];/* Array of device IDs.		    */
-
-} vid_subsys;
-
-/* API: get capability name/info */
-PJ_DEF(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
-					     const char **p_desc)
-{
-    const char *desc;
-    unsigned i;
-
-    if (p_desc==NULL) p_desc = &desc;
-
-    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
-	if ((1 << i)==cap)
-	    break;
-    }
-
-    if (i==PJ_ARRAY_SIZE(cap_infos)) {
-	*p_desc = "??";
-	return "??";
-    }
-
-    *p_desc = cap_infos[i].info;
-    return cap_infos[i].name;
-}
-
-static pj_status_t get_cap_pointer(const pjmedia_vid_dev_param *param,
-				   pjmedia_vid_dev_cap cap,
-				   void **ptr,
-				   unsigned *size)
-{
-#define FIELD_INFO(name)    *ptr = (void*)&param->name; \
-			    *size = sizeof(param->name)
-
-    switch (cap) {
-    case PJMEDIA_VID_DEV_CAP_FORMAT:
-	FIELD_INFO(fmt);
-	break;
-    case PJMEDIA_VID_DEV_CAP_INPUT_SCALE:
-	FIELD_INFO(disp_size);
-	break;
-    case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
-	FIELD_INFO(window);
-	break;
-    case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE:
-	FIELD_INFO(disp_size);
-	break;
-    case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION:
-	FIELD_INFO(window_pos);
-	break;
-    case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE:
-	FIELD_INFO(window_hide);
-	break;
-    case PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW:
-	FIELD_INFO(native_preview);
-	break;
-    case PJMEDIA_VID_DEV_CAP_ORIENTATION:
-	FIELD_INFO(orient);
-	break;
-    /* The PJMEDIA_VID_DEV_CAP_SWITCH does not have an entry in the
-     * param (it doesn't make sense to open a stream and tell it
-     * to switch immediately).
-     */
-    case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS:
-	FIELD_INFO(window_flags);
-	break;
-    default:
-	return PJMEDIA_EVID_INVCAP;
-    }
-
-#undef FIELD_INFO
-
-    return PJ_SUCCESS;
-}
-
-/* API: set cap value to param */
-PJ_DEF(pj_status_t)
-pjmedia_vid_dev_param_set_cap( pjmedia_vid_dev_param *param,
-			       pjmedia_vid_dev_cap cap,
-			       const void *pval)
-{
-    void *cap_ptr;
-    unsigned cap_size;
-    pj_status_t status;
-
-    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    pj_memcpy(cap_ptr, pval, cap_size);
-    param->flags |= cap;
-
-    return PJ_SUCCESS;
-}
-
-/* API: get cap value from param */
-PJ_DEF(pj_status_t)
-pjmedia_vid_dev_param_get_cap( const pjmedia_vid_dev_param *param,
-			       pjmedia_vid_dev_cap cap,
-			       void *pval)
-{
-    void *cap_ptr;
-    unsigned cap_size;
-    pj_status_t status;
-
-    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    if ((param->flags & cap) == 0) {
-	pj_bzero(cap_ptr, cap_size);
-	return PJMEDIA_EVID_INVCAP;
-    }
-
-    pj_memcpy(pval, cap_ptr, cap_size);
-    return PJ_SUCCESS;
-}
-
-/* Internal: init driver */
-static pj_status_t init_driver(unsigned drv_idx, pj_bool_t refresh)
-{
-    struct driver *drv = &vid_subsys.drv[drv_idx];
-    pjmedia_vid_dev_factory *f;
-    unsigned i, dev_cnt;
-    pj_status_t status;
-
-    if (!refresh) {
-        /* Create the factory */
-        f = (*drv->create)(vid_subsys.pf);
-        if (!f)
-            return PJ_EUNKNOWN;
-
-        /* Call factory->init() */
-        status = f->op->init(f);
-        if (status != PJ_SUCCESS) {
-            f->op->destroy(f);
-            return status;
-        }
-    } else {
-	f = drv->f;
-    }
-
-    /* Get number of devices */
-    dev_cnt = f->op->get_dev_count(f);
-    if (dev_cnt + vid_subsys.dev_cnt > MAX_DEVS) {
-	PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
-			      " there are too many devices",
-			      vid_subsys.dev_cnt + dev_cnt - MAX_DEVS));
-	dev_cnt = MAX_DEVS - vid_subsys.dev_cnt;
-    }
-
-    /* enabling this will cause pjsua-lib initialization to fail when there
-     * is no video device installed in the system, even when pjsua has been
-     * run with --null-video
-     *
-    if (dev_cnt == 0) {
-	f->op->destroy(f);
-	return PJMEDIA_EVID_NODEV;
-    }
-    */
-
-    /* Fill in default devices */
-    drv->rend_dev_idx = drv->cap_dev_idx = -1;
-    for (i=0; i<dev_cnt; ++i) {
-	pjmedia_vid_dev_info info;
-
-	status = f->op->get_dev_info(f, i, &info);
-	if (status != PJ_SUCCESS) {
-	    f->op->destroy(f);
-	    return status;
-	}
-
-	if (drv->name[0]=='\0') {
-	    /* Set driver name */
-	    pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
-	    drv->name[sizeof(drv->name)-1] = '\0';
-	}
-
-	if (drv->rend_dev_idx < 0 && (info.dir & PJMEDIA_DIR_RENDER)) {
-	    /* Set default render device */
-	    drv->rend_dev_idx = i;
-	}
-	if (drv->cap_dev_idx < 0 && (info.dir & PJMEDIA_DIR_CAPTURE)) {
-	    /* Set default capture device */
-	    drv->cap_dev_idx = i;
-	}
-
-        if (drv->rend_dev_idx >= 0 && drv->cap_dev_idx >= 0) {
-	    /* Done. */
-	    break;
-	}
-    }
-
-    /* Register the factory */
-    drv->f = f;
-    drv->f->sys.drv_idx = drv_idx;
-    drv->start_idx = vid_subsys.dev_cnt;
-    drv->dev_cnt = dev_cnt;
-
-    /* Register devices to global list */
-    for (i=0; i<dev_cnt; ++i) {
-	vid_subsys.dev_list[vid_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
-    }
-
-    return PJ_SUCCESS;
-}
-
-/* Internal: deinit driver */
-static void deinit_driver(unsigned drv_idx)
-{
-    struct driver *drv = &vid_subsys.drv[drv_idx];
-
-    if (drv->f) {
-	drv->f->op->destroy(drv->f);
-	drv->f = NULL;
-    }
-
-    drv->dev_cnt = 0;
-    drv->rend_dev_idx = drv->cap_dev_idx = -1;
-}
-
 /* API: Initialize the video device subsystem. */
 PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_init(pj_pool_factory *pf)
@@ -361,9 +77,10 @@
     unsigned i;
     pj_status_t status = PJ_SUCCESS;
+    pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys();
 
     /* Allow init() to be called multiple times as long as there is matching
      * number of shutdown().
      */
-    if (vid_subsys.init_count++ != 0) {
+    if (vid_subsys->init_count++ != 0) {
 	return PJ_SUCCESS;
     }
@@ -375,32 +92,32 @@
 
     /* Init */
-    vid_subsys.pf = pf;
-    vid_subsys.drv_cnt = 0;
-    vid_subsys.dev_cnt = 0;
+    vid_subsys->pf = pf;
+    vid_subsys->drv_cnt = 0;
+    vid_subsys->dev_cnt = 0;
 
     /* Register creation functions */
 #if PJMEDIA_VIDEO_DEV_HAS_V4L2
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_v4l2_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_v4l2_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_QT
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_qt_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_qt_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_OPENGL
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_opengl_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_opengl_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_IOS
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ios_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_ios_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_DSHOW
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_dshow_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_dshow_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_FFMPEG
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_ffmpeg_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_ffmpeg_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_SDL
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_sdl_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_sdl_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_ANDROID
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_and_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_and_factory;
 #endif
 #if PJMEDIA_VIDEO_DEV_HAS_CBAR_SRC
@@ -408,17 +125,17 @@
      * a real capturer, if any.
      */
-    vid_subsys.drv[vid_subsys.drv_cnt++].create = &pjmedia_cbar_factory;
+    vid_subsys->drv[vid_subsys->drv_cnt++].create = &pjmedia_cbar_factory;
 #endif
 
     /* Initialize each factory and build the device ID list */
-    for (i=0; i<vid_subsys.drv_cnt; ++i) {
-	status = init_driver(i, PJ_FALSE);
+    for (i=0; i<vid_subsys->drv_cnt; ++i) {
+	status = pjmedia_vid_driver_init(i, PJ_FALSE);
 	if (status != PJ_SUCCESS) {
-	    deinit_driver(i);
+	    pjmedia_vid_driver_deinit(i);
 	    continue;
 	}
     }
 
-    return vid_subsys.dev_cnt ? PJ_SUCCESS : status;
+    return vid_subsys->dev_cnt ? PJ_SUCCESS : status;
 }
 
@@ -430,10 +147,11 @@
     pj_bool_t refresh = PJ_FALSE;
     pj_status_t status;
-
-    if (vid_subsys.init_count == 0)
+    pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys();
+
+    if (vid_subsys->init_count == 0)
 	return PJMEDIA_EVID_INIT;
 
-    vid_subsys.drv[vid_subsys.drv_cnt].create = adf;
-    vid_subsys.drv[vid_subsys.drv_cnt].f = factory;
+    vid_subsys->drv[vid_subsys->drv_cnt].create = adf;
+    vid_subsys->drv[vid_subsys->drv_cnt].f = factory;
 
     if (factory) {
@@ -447,9 +165,9 @@
     }
 
-    status = init_driver(vid_subsys.drv_cnt, refresh);
+    status = pjmedia_vid_driver_init(vid_subsys->drv_cnt, refresh);
     if (status == PJ_SUCCESS) {
-	vid_subsys.drv_cnt++;
+	vid_subsys->drv_cnt++;
     } else {
-	deinit_driver(vid_subsys.drv_cnt);
+	pjmedia_vid_driver_deinit(vid_subsys->drv_cnt);
     }
 
@@ -463,18 +181,19 @@
 {
     unsigned i, j;
-
-    if (vid_subsys.init_count == 0)
+    pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys();
+
+    if (vid_subsys->init_count == 0)
 	return PJMEDIA_EVID_INIT;
 
-    for (i=0; i<vid_subsys.drv_cnt; ++i) {
-	struct driver *drv = &vid_subsys.drv[i];
+    for (i=0; i<vid_subsys->drv_cnt; ++i) {
+	pjmedia_vid_driver *drv = &vid_subsys->drv[i];
 
 	if ((factory && drv->f==factory) || (adf && drv->create == adf)) {
 	    for (j = drv->start_idx; j < drv->start_idx + drv->dev_cnt; j++)
 	    {
-		vid_subsys.dev_list[j] = (pj_uint32_t)PJMEDIA_VID_INVALID_DEV;
+		vid_subsys->dev_list[j] = (pj_uint32_t)PJMEDIA_VID_INVALID_DEV;
 	    }
 
-	    deinit_driver(i);
+	    pjmedia_vid_driver_deinit(i);
 	    pj_bzero(drv, sizeof(*drv));
 	    return PJ_SUCCESS;
@@ -488,5 +207,6 @@
 PJ_DEF(pj_pool_factory*) pjmedia_vid_dev_subsys_get_pool_factory(void)
 {
-    return vid_subsys.pf;
+    pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys();
+    return vid_subsys->pf;
 }
 
@@ -495,421 +215,24 @@
 {
     unsigned i;
+    pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys();
 
     /* Allow shutdown() to be called multiple times as long as there is
      * matching number of init().
      */
-    if (vid_subsys.init_count == 0) {
+    if (vid_subsys->init_count == 0) {
 	return PJ_SUCCESS;
     }
-    --vid_subsys.init_count;
-
-    if (vid_subsys.init_count == 0) {
-        for (i=0; i<vid_subsys.drv_cnt; ++i) {
-	    deinit_driver(i);
+    --vid_subsys->init_count;
+
+    if (vid_subsys->init_count == 0) {
+        for (i=0; i<vid_subsys->drv_cnt; ++i) {
+	    pjmedia_vid_driver_deinit(i);
         }
 
-        vid_subsys.pf = NULL;
+        vid_subsys->pf = NULL;
     }
     return PJ_SUCCESS;
 }
 
-/* API: Refresh the list of video devices installed in the system. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void)
-{
-    unsigned i;
-    
-    vid_subsys.dev_cnt = 0;
-    for (i=0; i<vid_subsys.drv_cnt; ++i) {
-	struct driver *drv = &vid_subsys.drv[i];
-	
-	if (drv->f && drv->f->op->refresh) {
-	    pj_status_t status = drv->f->op->refresh(drv->f);
-	    if (status != PJ_SUCCESS) {
-		PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
-						 "list for %s", drv->name));
-	    }
-	}
-	init_driver(i, PJ_TRUE);
-    }
-    return PJ_SUCCESS;
-}
-
-/* API: Get the number of video devices installed in the system. */
-PJ_DEF(unsigned) pjmedia_vid_dev_count(void)
-{
-    return vid_subsys.dev_cnt;
-}
-
-/* Internal: convert local index to global device index */
-static pj_status_t make_global_index(unsigned drv_idx, 
-				     pjmedia_vid_dev_index *id)
-{
-    if (*id < 0) {
-	return PJ_SUCCESS;
-    }
-
-    /* Check that factory still exists */
-    PJ_ASSERT_RETURN(vid_subsys.drv[drv_idx].f, PJ_EBUG);
-
-    /* Check that device index is valid */
-    PJ_ASSERT_RETURN(*id>=0 && *id<(int)vid_subsys.drv[drv_idx].dev_cnt, 
-		     PJ_EBUG);
-
-    *id += vid_subsys.drv[drv_idx].start_idx;
-    return PJ_SUCCESS;
-}
-
-/* Internal: lookup device id */
-static pj_status_t lookup_dev(pjmedia_vid_dev_index id,
-			      pjmedia_vid_dev_factory **p_f,
-			      unsigned *p_local_index)
-{
-    int f_id, index;
-
-    if (id < 0) {
-	unsigned i;
-
-	if (id <= PJMEDIA_VID_INVALID_DEV)
-	    return PJMEDIA_EVID_INVDEV;
-
-	for (i=0; i<vid_subsys.drv_cnt; ++i) {
-	    struct driver *drv = &vid_subsys.drv[i];
-	    if (id==PJMEDIA_VID_DEFAULT_CAPTURE_DEV && 
-		drv->cap_dev_idx >= 0) 
-	    {
-		id = drv->cap_dev_idx;
-		make_global_index(i, &id);
-		break;
-	    } else if (id==PJMEDIA_VID_DEFAULT_RENDER_DEV && 
-		drv->rend_dev_idx >= 0) 
-	    {
-		id = drv->rend_dev_idx;
-		make_global_index(i, &id);
-		break;
-	    }
-	}
-
-	if (id < 0) {
-	    return PJMEDIA_EVID_NODEFDEV;
-	}
-    }
-
-    f_id = GET_FID(vid_subsys.dev_list[id]);
-    index = GET_INDEX(vid_subsys.dev_list[id]);
-
-    if (f_id < 0 || f_id >= (int)vid_subsys.drv_cnt)
-	return PJMEDIA_EVID_INVDEV;
-
-    if (index < 0 || index >= (int)vid_subsys.drv[f_id].dev_cnt)
-	return PJMEDIA_EVID_INVDEV;
-
-    *p_f = vid_subsys.drv[f_id].f;
-    *p_local_index = (unsigned)index;
-
-    return PJ_SUCCESS;
-
-}
-
-/* API: lookup device id */
-PJ_DEF(pj_status_t)
-pjmedia_vid_dev_get_local_index(pjmedia_vid_dev_index id,
-                                pjmedia_vid_dev_factory **p_f,
-                                unsigned *p_local_index)
-{
-    return lookup_dev(id, p_f, p_local_index);
-}
-
-/* API: from factory and local index, get global index */
-PJ_DEF(pj_status_t)
-pjmedia_vid_dev_get_global_index(const pjmedia_vid_dev_factory *f,
-                                 unsigned local_idx,
-                                 pjmedia_vid_dev_index *pid)
-{
-    PJ_ASSERT_RETURN(f->sys.drv_idx >= 0 && f->sys.drv_idx < MAX_DRIVERS,
-                     PJ_EINVALIDOP);
-    *pid = local_idx;
-    return make_global_index(f->sys.drv_idx, pid);
-}
-
-/* API: Get device information. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
-					     pjmedia_vid_dev_info *info)
-{
-    pjmedia_vid_dev_factory *f;
-    unsigned index;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(info, PJ_EINVAL);
-    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
-
-    if (id <= PJMEDIA_VID_INVALID_DEV)
-	return PJMEDIA_EVID_INVDEV;
-
-    status = lookup_dev(id, &f, &index);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    status = f->op->get_dev_info(f, index, info);
-
-    /* Make sure device ID is the real ID (not PJMEDIA_VID_DEFAULT_*_DEV) */
-    info->id = index;
-    make_global_index(f->sys.drv_idx, &info->id);
-
-    return status;
-}
-
-/* API: find device */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_lookup( const char *drv_name,
-					    const char *dev_name,
-					    pjmedia_vid_dev_index *id)
-{
-    pjmedia_vid_dev_factory *f = NULL;
-    unsigned drv_idx, dev_idx;
-
-    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
-    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
-
-    for (drv_idx=0; drv_idx<vid_subsys.drv_cnt; ++drv_idx) {
-	if (!pj_ansi_stricmp(drv_name, vid_subsys.drv[drv_idx].name))
-	{
-	    f = vid_subsys.drv[drv_idx].f;
-	    break;
-	}
-    }
-
-    if (!f)
-	return PJ_ENOTFOUND;
-
-    for (dev_idx=0; dev_idx<vid_subsys.drv[drv_idx].dev_cnt; ++dev_idx)
-    {
-	pjmedia_vid_dev_info info;
-	pj_status_t status;
-
-	status = f->op->get_dev_info(f, dev_idx, &info);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	if (!pj_ansi_stricmp(dev_name, info.name))
-	    break;
-    }
-
-    if (dev_idx==vid_subsys.drv[drv_idx].dev_cnt)
-	return PJ_ENOTFOUND;
-
-    *id = dev_idx;
-    make_global_index(drv_idx, id);
-
-    return PJ_SUCCESS;
-}
-
-/* API: Initialize the video device parameters with default values for the
- * specified device.
- */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_default_param(pj_pool_t *pool,
-                                                  pjmedia_vid_dev_index id,
-						  pjmedia_vid_dev_param *param)
-{
-    pjmedia_vid_dev_factory *f;
-    unsigned index;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(param, PJ_EINVAL);
-    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
-
-    if (id <= PJMEDIA_VID_INVALID_DEV)
-	return PJMEDIA_EVID_INVDEV;
-
-    status = lookup_dev(id, &f, &index);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    status = f->op->default_param(pool, f, index, param);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Normalize device IDs */
-    make_global_index(f->sys.drv_idx, &param->cap_id);
-    make_global_index(f->sys.drv_idx, &param->rend_id);
-
-    return PJ_SUCCESS;
-}
-
-/* API: Open video stream object using the specified parameters. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_create(
-					pjmedia_vid_dev_param *prm,
-					const pjmedia_vid_dev_cb *cb,
-					void *user_data,
-					pjmedia_vid_dev_stream **p_vid_strm)
-{
-    pjmedia_vid_dev_factory *cap_f=NULL, *rend_f=NULL, *f=NULL;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(prm && prm->dir && p_vid_strm, PJ_EINVAL);
-    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
-    PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
-		     prm->dir==PJMEDIA_DIR_RENDER ||
-		     prm->dir==PJMEDIA_DIR_CAPTURE_RENDER,
-		     PJ_EINVAL);
-
-    /* Normalize cap_id */
-    if (prm->dir & PJMEDIA_DIR_CAPTURE) {
-	unsigned index;
-
-	if (prm->cap_id < 0)
-	    prm->cap_id = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
-
-	status = lookup_dev(prm->cap_id, &cap_f, &index);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	prm->cap_id = index;
-	f = cap_f;
-    }
-
-    /* Normalize rend_id */
-    if (prm->dir & PJMEDIA_DIR_RENDER) {
-	unsigned index;
-
-	if (prm->rend_id < 0)
-	    prm->rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
-
-	status = lookup_dev(prm->rend_id, &rend_f, &index);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	prm->rend_id = index;
-	f = rend_f;
-    }
-
-    PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
-
-    /* For now, cap_id and rend_id must belong to the same factory */
-    PJ_ASSERT_RETURN((prm->dir != PJMEDIA_DIR_CAPTURE_RENDER) ||
-		     (cap_f == rend_f),
-		     PJMEDIA_EVID_INVDEV);
-
-    /* Create the stream */
-    status = f->op->create_stream(f, prm, cb,
-				  user_data, p_vid_strm);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Assign factory id to the stream */
-    (*p_vid_strm)->sys.drv_idx = f->sys.drv_idx;
-    return PJ_SUCCESS;
-}
-
-/* API: Get the running parameters for the specified video stream. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_param(
-					    pjmedia_vid_dev_stream *strm,
-					    pjmedia_vid_dev_param *param)
-{
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
-    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
-
-    status = strm->op->get_param(strm, param);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Normalize device id's */
-    make_global_index(strm->sys.drv_idx, &param->cap_id);
-    make_global_index(strm->sys.drv_idx, &param->rend_id);
-
-    return PJ_SUCCESS;
-}
-
-/* API: Get the value of a specific capability of the video stream. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_cap(
-					    pjmedia_vid_dev_stream *strm,
-					    pjmedia_vid_dev_cap cap,
-					    void *value)
-{
-    return strm->op->get_cap(strm, cap, value);
-}
-
-/* API: Set the value of a specific capability of the video stream. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_set_cap(
-					    pjmedia_vid_dev_stream *strm,
-					    pjmedia_vid_dev_cap cap,
-					    const void *value)
-{
-    /* For fast switching, device global index needs to be converted to
-     * local index before forwarding the request to the device stream.
-     */
-    if (cap == PJMEDIA_VID_DEV_CAP_SWITCH) {
-	pjmedia_vid_dev_factory *f;
-	unsigned local_idx;
-	pj_status_t status;
-	pjmedia_vid_dev_switch_param p = *(pjmedia_vid_dev_switch_param*)value;
-
-	status = lookup_dev(p.target_id, &f, &local_idx);
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	/* Make sure that current & target devices share the same factory */
-	if (f->sys.drv_idx != strm->sys.drv_idx)
-	    return PJMEDIA_EVID_INVDEV;
-
-	p.target_id = local_idx;
-	return strm->op->set_cap(strm, cap, &p);
-    }
-
-    return strm->op->set_cap(strm, cap, value);
-}
-
-/* API: Start the stream. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
-{
-    pj_status_t status;
-
-    if (pjmedia_vid_dev_stream_is_running(strm))
-	return PJ_SUCCESS;
-
-    status = strm->op->start(strm);
-    if (status == PJ_SUCCESS)
-	strm->sys.is_running = PJ_TRUE;
-    return status;
-}
-
-/* API: has it been started? */
-PJ_DEF(pj_bool_t)
-pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm)
-{
-    return strm->sys.is_running;
-}
-
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_frame(
-					    pjmedia_vid_dev_stream *strm,
-					    pjmedia_frame *frame)
-{
-    pj_assert(strm->op->get_frame);
-    return strm->op->get_frame(strm, frame);
-}
-
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_put_frame(
-					    pjmedia_vid_dev_stream *strm,
-                                            const pjmedia_frame *frame)
-{
-    pj_assert(strm->op->put_frame);
-    return strm->op->put_frame(strm, frame);
-}
-
-/* API: Stop the stream. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
-{
-    strm->sys.is_running = PJ_FALSE;
-    return strm->op->stop(strm);
-}
-
-/* API: Destroy the stream. */
-PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_destroy(
-						pjmedia_vid_dev_stream *strm)
-{
-    strm->sys.is_running = PJ_FALSE;
-    return strm->op->destroy(strm);
-}
-
 
 #endif /* PJMEDIA_HAS_VIDEO */
Index: /pjproject/trunk/pjmedia/src/pjmedia/audiodev.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/audiodev.c	(revision 5255)
+++ /pjproject/trunk/pjmedia/src/pjmedia/audiodev.c	(revision 5255)
@@ -0,0 +1,628 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia-audiodev/audiodev_imp.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/log.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+#define THIS_FILE   "audiodev.c"
+
+#define DEFINE_CAP(name, info)	{name, info}
+
+/* Capability names */
+static struct cap_info
+{
+    const char *name;
+    const char *info;
+} cap_infos[] = 
+{
+    DEFINE_CAP("ext-fmt",     "Extended/non-PCM format"),
+    DEFINE_CAP("latency-in",  "Input latency/buffer size setting"),
+    DEFINE_CAP("latency-out", "Output latency/buffer size setting"),
+    DEFINE_CAP("vol-in",      "Input volume setting"),
+    DEFINE_CAP("vol-out",     "Output volume setting"),
+    DEFINE_CAP("meter-in",    "Input meter"),
+    DEFINE_CAP("meter-out",   "Output meter"),
+    DEFINE_CAP("route-in",    "Input routing"),
+    DEFINE_CAP("route-out",   "Output routing"),
+    DEFINE_CAP("aec",	      "Accoustic echo cancellation"),
+    DEFINE_CAP("aec-tail",    "Tail length setting for AEC"),
+    DEFINE_CAP("vad",	      "Voice activity detection"),
+    DEFINE_CAP("cng",	      "Comfort noise generation"),
+    DEFINE_CAP("plg",	      "Packet loss concealment")
+};
+
+
+/*
+ * The device index seen by application and driver is different. 
+ *
+ * At application level, device index is index to global list of device.
+ * At driver level, device index is index to device list on that particular
+ * factory only.
+ */
+#define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
+#define GET_INDEX(dev_id)	   ((dev_id) & 0xFFFF)
+#define GET_FID(dev_id)		   ((dev_id) >> 16)
+#define DEFAULT_DEV_ID		    0
+
+
+/* The audio subsystem */
+static pjmedia_aud_subsys aud_subsys;
+
+/* API: get the audio subsystem. */
+PJ_DEF(pjmedia_aud_subsys*) pjmedia_get_aud_subsys(void)
+{
+    return &aud_subsys;
+}
+
+/* API: init driver */
+PJ_DEF(pj_status_t) pjmedia_aud_driver_init(unsigned drv_idx,
+					    pj_bool_t refresh)
+{
+    pjmedia_aud_driver *drv = &aud_subsys.drv[drv_idx];
+    pjmedia_aud_dev_factory *f;
+    unsigned i, dev_cnt;
+    pj_status_t status;
+
+    if (!refresh && drv->create) {
+	/* Create the factory */
+	f = (*drv->create)(aud_subsys.pf);
+	if (!f)
+	    return PJ_EUNKNOWN;
+
+	/* Call factory->init() */
+	status = f->op->init(f);
+	if (status != PJ_SUCCESS) {
+	    f->op->destroy(f);
+	    return status;
+	}
+    } else {
+	f = drv->f;
+    }
+
+    if (!f)
+	return PJ_EUNKNOWN;
+
+    /* Get number of devices */
+    dev_cnt = f->op->get_dev_count(f);
+    if (dev_cnt + aud_subsys.dev_cnt > PJMEDIA_AUD_MAX_DEVS) {
+	PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
+			      " there are too many devices",
+			      aud_subsys.dev_cnt + dev_cnt -
+			      PJMEDIA_AUD_MAX_DEVS));
+	dev_cnt = PJMEDIA_AUD_MAX_DEVS - aud_subsys.dev_cnt;
+    }
+
+    /* enabling this will cause pjsua-lib initialization to fail when there
+     * is no sound device installed in the system, even when pjsua has been
+     * run with --null-audio
+     *
+    if (dev_cnt == 0) {
+	f->op->destroy(f);
+	return PJMEDIA_EAUD_NODEV;
+    }
+    */
+
+    /* Fill in default devices */
+    drv->play_dev_idx = drv->rec_dev_idx =
+			drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;
+    for (i=0; i<dev_cnt; ++i) {
+	pjmedia_aud_dev_info info;
+
+	status = f->op->get_dev_info(f, i, &info);
+	if (status != PJ_SUCCESS) {
+	    f->op->destroy(f);
+	    return status;
+	}
+
+	if (drv->name[0]=='\0') {
+	    /* Set driver name */
+	    pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
+	    drv->name[sizeof(drv->name)-1] = '\0';
+	}
+
+	if (drv->play_dev_idx < 0 && info.output_count) {
+	    /* Set default playback device */
+	    drv->play_dev_idx = i;
+	}
+	if (drv->rec_dev_idx < 0 && info.input_count) {
+	    /* Set default capture device */
+	    drv->rec_dev_idx = i;
+	}
+	if (drv->dev_idx < 0 && info.input_count &&
+	    info.output_count)
+	{
+	    /* Set default capture and playback device */
+	    drv->dev_idx = i;
+	}
+
+	if (drv->play_dev_idx >= 0 && drv->rec_dev_idx >= 0 && 
+	    drv->dev_idx >= 0) 
+	{
+	    /* Done. */
+	    break;
+	}
+    }
+
+    /* Register the factory */
+    drv->f = f;
+    drv->f->sys.drv_idx = drv_idx;
+    drv->start_idx = aud_subsys.dev_cnt;
+    drv->dev_cnt = dev_cnt;
+
+    /* Register devices to global list */
+    for (i=0; i<dev_cnt; ++i) {
+	aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: deinit driver */
+PJ_DEF(void) pjmedia_aud_driver_deinit(unsigned drv_idx)
+{
+    pjmedia_aud_driver *drv = &aud_subsys.drv[drv_idx];
+
+    if (drv->f) {
+	drv->f->op->destroy(drv->f);
+	drv->f = NULL;
+    }
+
+    pj_bzero(drv, sizeof(*drv));
+    drv->play_dev_idx = drv->rec_dev_idx = 
+			drv->dev_idx = PJMEDIA_AUD_INVALID_DEV;
+}
+
+/* API: get capability name/info */
+PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
+					     const char **p_desc)
+{
+    const char *desc;
+    unsigned i;
+
+    if (p_desc==NULL) p_desc = &desc;
+
+    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
+	if ((1 << i)==cap)
+	    break;
+    }
+
+    if (i==PJ_ARRAY_SIZE(cap_infos)) {
+	*p_desc = "??";
+	return "??";
+    }
+
+    *p_desc = cap_infos[i].info;
+    return cap_infos[i].name;
+}
+
+static pj_status_t get_cap_pointer(const pjmedia_aud_param *param,
+				   pjmedia_aud_dev_cap cap,
+				   void **ptr,
+				   unsigned *size)
+{
+#define FIELD_INFO(name)    *ptr = (void*)&param->name; \
+			    *size = sizeof(param->name)
+
+    switch (cap) {
+    case PJMEDIA_AUD_DEV_CAP_EXT_FORMAT:
+	FIELD_INFO(ext_fmt);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY:
+	FIELD_INFO(input_latency_ms);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY:
+	FIELD_INFO(output_latency_ms);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
+	FIELD_INFO(input_vol);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
+	FIELD_INFO(output_vol);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE:
+	FIELD_INFO(input_route);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
+	FIELD_INFO(output_route);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_EC:
+	FIELD_INFO(ec_enabled);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_EC_TAIL:
+	FIELD_INFO(ec_tail_ms);
+	break;
+    /* vad is no longer in "fmt" in 2.0.
+    case PJMEDIA_AUD_DEV_CAP_VAD:
+	FIELD_INFO(ext_fmt.vad);
+	break;
+    */
+    case PJMEDIA_AUD_DEV_CAP_CNG:
+	FIELD_INFO(cng_enabled);
+	break;
+    case PJMEDIA_AUD_DEV_CAP_PLC:
+	FIELD_INFO(plc_enabled);
+	break;
+    default:
+	return PJMEDIA_EAUD_INVCAP;
+    }
+
+#undef FIELD_INFO
+
+    return PJ_SUCCESS;
+}
+
+/* API: set cap value to param */
+PJ_DEF(pj_status_t) pjmedia_aud_param_set_cap( pjmedia_aud_param *param,
+					       pjmedia_aud_dev_cap cap,
+					       const void *pval)
+{
+    void *cap_ptr;
+    unsigned cap_size;
+    pj_status_t status;
+
+    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_memcpy(cap_ptr, pval, cap_size);
+    param->flags |= cap;
+
+    return PJ_SUCCESS;
+}
+
+/* API: get cap value from param */
+PJ_DEF(pj_status_t) pjmedia_aud_param_get_cap( const pjmedia_aud_param *param,
+					       pjmedia_aud_dev_cap cap,
+					       void *pval)
+{
+    void *cap_ptr;
+    unsigned cap_size;
+    pj_status_t status;
+
+    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if ((param->flags & cap) == 0) {
+	pj_bzero(cap_ptr, cap_size);
+	return PJMEDIA_EAUD_INVCAP;
+    }
+
+    pj_memcpy(pval, cap_ptr, cap_size);
+    return PJ_SUCCESS;
+}
+
+
+/* API: Refresh the list of sound devices installed in the system. */
+PJ_DEF(pj_status_t) pjmedia_aud_dev_refresh(void)
+{
+    unsigned i;
+    
+    aud_subsys.dev_cnt = 0;
+    for (i=0; i<aud_subsys.drv_cnt; ++i) {
+	pjmedia_aud_driver *drv = &aud_subsys.drv[i];
+	
+	if (drv->f && drv->f->op->refresh) {
+	    pj_status_t status = drv->f->op->refresh(drv->f);
+	    if (status != PJ_SUCCESS) {
+		PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
+						 "list for %s", drv->name));
+	    }
+	}
+	pjmedia_aud_driver_init(i, PJ_TRUE);
+    }
+    return PJ_SUCCESS;
+}
+
+/* API: Get the number of sound devices installed in the system. */
+PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
+{
+    return aud_subsys.dev_cnt;
+}
+
+/* Internal: convert local index to global device index */
+static pj_status_t make_global_index(unsigned drv_idx, 
+				     pjmedia_aud_dev_index *id)
+{
+    if (*id < 0) {
+	return PJ_SUCCESS;
+    }
+
+    /* Check that factory still exists */
+    PJ_ASSERT_RETURN(aud_subsys.drv[drv_idx].f, PJ_EBUG);
+
+    /* Check that device index is valid */
+    PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[drv_idx].dev_cnt, 
+		     PJ_EBUG);
+
+    *id += aud_subsys.drv[drv_idx].start_idx;
+    return PJ_SUCCESS;
+}
+
+/* Internal: lookup device id */
+static pj_status_t lookup_dev(pjmedia_aud_dev_index id,
+			      pjmedia_aud_dev_factory **p_f,
+			      unsigned *p_local_index)
+{
+    int f_id, index;
+
+    if (id < 0) {
+	unsigned i;
+
+	if (id == PJMEDIA_AUD_INVALID_DEV)
+	    return PJMEDIA_EAUD_INVDEV;
+
+	for (i=0; i<aud_subsys.drv_cnt; ++i) {
+	    pjmedia_aud_driver *drv = &aud_subsys.drv[i];
+	    if (drv->dev_idx >= 0) {
+		id = drv->dev_idx;
+		make_global_index(i, &id);
+		break;
+	    } else if (id==PJMEDIA_AUD_DEFAULT_CAPTURE_DEV && 
+		drv->rec_dev_idx >= 0) 
+	    {
+		id = drv->rec_dev_idx;
+		make_global_index(i, &id);
+		break;
+	    } else if (id==PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV && 
+		drv->play_dev_idx >= 0) 
+	    {
+		id = drv->play_dev_idx;
+		make_global_index(i, &id);
+		break;
+	    }
+	}
+
+	if (id < 0) {
+	    return PJMEDIA_EAUD_NODEFDEV;
+	}
+    }
+
+    f_id = GET_FID(aud_subsys.dev_list[id]);
+    index = GET_INDEX(aud_subsys.dev_list[id]);
+
+    if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
+	return PJMEDIA_EAUD_INVDEV;
+
+    if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
+	return PJMEDIA_EAUD_INVDEV;
+
+    *p_f = aud_subsys.drv[f_id].f;
+    *p_local_index = (unsigned)index;
+
+    return PJ_SUCCESS;
+
+}
+
+/* API: Get device information. */
+PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
+					     pjmedia_aud_dev_info *info)
+{
+    pjmedia_aud_dev_factory *f;
+    unsigned index;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(info && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
+    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
+
+    status = lookup_dev(id, &f, &index);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    return f->op->get_dev_info(f, index, info);
+}
+
+/* API: find device */
+PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,
+					    const char *dev_name,
+					    pjmedia_aud_dev_index *id)
+{
+    pjmedia_aud_dev_factory *f = NULL;
+    unsigned drv_idx, dev_idx;
+
+    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
+    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
+
+    for (drv_idx=0; drv_idx<aud_subsys.drv_cnt; ++drv_idx) {
+	if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[drv_idx].name)) {
+	    f = aud_subsys.drv[drv_idx].f;
+	    break;
+	}
+    }
+
+    if (!f)
+	return PJ_ENOTFOUND;
+
+    for (dev_idx=0; dev_idx<aud_subsys.drv[drv_idx].dev_cnt; ++dev_idx) {
+	pjmedia_aud_dev_info info;
+	pj_status_t status;
+
+	status = f->op->get_dev_info(f, dev_idx, &info);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	if (!pj_ansi_stricmp(dev_name, info.name))
+	    break;
+    }
+
+    if (dev_idx==aud_subsys.drv[drv_idx].dev_cnt)
+	return PJ_ENOTFOUND;
+
+    *id = dev_idx;
+    make_global_index(drv_idx, id);
+
+    return PJ_SUCCESS;
+}
+
+/* API: Initialize the audio device parameters with default values for the
+ * specified device.
+ */
+PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
+						  pjmedia_aud_param *param)
+{
+    pjmedia_aud_dev_factory *f;
+    unsigned index;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(param && id!=PJMEDIA_AUD_INVALID_DEV, PJ_EINVAL);
+    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
+
+    status = lookup_dev(id, &f, &index);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = f->op->default_param(f, index, param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Normalize device IDs */
+    make_global_index(f->sys.drv_idx, &param->rec_id);
+    make_global_index(f->sys.drv_idx, &param->play_id);
+
+    return PJ_SUCCESS;
+}
+
+/* API: Open audio stream object using the specified parameters. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,
+					      pjmedia_aud_rec_cb rec_cb,
+					      pjmedia_aud_play_cb play_cb,
+					      void *user_data,
+					      pjmedia_aud_stream **p_aud_strm)
+{
+    pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
+    pjmedia_aud_param param;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);
+    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
+    PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
+		     prm->dir==PJMEDIA_DIR_PLAYBACK ||
+		     prm->dir==PJMEDIA_DIR_CAPTURE_PLAYBACK,
+		     PJ_EINVAL);
+
+    /* Must make copy of param because we're changing device ID */
+    pj_memcpy(&param, prm, sizeof(param));
+
+    /* Normalize rec_id */
+    if (param.dir & PJMEDIA_DIR_CAPTURE) {
+	unsigned index;
+
+	if (param.rec_id < 0)
+	    param.rec_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
+
+	status = lookup_dev(param.rec_id, &rec_f, &index);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	param.rec_id = index;
+	f = rec_f;
+    }
+
+    /* Normalize play_id */
+    if (param.dir & PJMEDIA_DIR_PLAYBACK) {
+	unsigned index;
+
+	if (param.play_id < 0)
+	    param.play_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
+
+	status = lookup_dev(param.play_id, &play_f, &index);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	param.play_id = index;
+	f = play_f;
+    }
+
+    PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
+
+    /* For now, rec_id and play_id must belong to the same factory */
+    PJ_ASSERT_RETURN((param.dir != PJMEDIA_DIR_CAPTURE_PLAYBACK) || 
+		     (rec_f == play_f),
+		     PJMEDIA_EAUD_INVDEV);
+
+    /* Create the stream */
+    status = f->op->create_stream(f, &param, rec_cb, play_cb,
+				  user_data, p_aud_strm);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Assign factory id to the stream */
+    (*p_aud_strm)->sys.drv_idx = f->sys.drv_idx;
+    return PJ_SUCCESS;
+}
+
+/* API: Get the running parameters for the specified audio stream. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
+						 pjmedia_aud_param *param)
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
+    PJ_ASSERT_RETURN(aud_subsys.pf, PJMEDIA_EAUD_INIT);
+
+    status = strm->op->get_param(strm, param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Normalize device id's */
+    make_global_index(strm->sys.drv_idx, &param->rec_id);
+    make_global_index(strm->sys.drv_idx, &param->play_id);
+
+    return PJ_SUCCESS;
+}
+
+/* API: Get the value of a specific capability of the audio stream. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm,
+					       pjmedia_aud_dev_cap cap,
+					       void *value)
+{
+    return strm->op->get_cap(strm, cap, value);
+}
+
+/* API: Set the value of a specific capability of the audio stream. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm,
+					       pjmedia_aud_dev_cap cap,
+					       const void *value)
+{
+    return strm->op->set_cap(strm, cap, value);
+}
+
+/* API: Start the stream. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm)
+{
+    return strm->op->start(strm);
+}
+
+/* API: Stop the stream. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm)
+{
+    return strm->op->stop(strm);
+}
+
+/* API: Destroy the stream. */
+PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm)
+{
+    return strm->op->destroy(strm);
+}
+
+
Index: /pjproject/trunk/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 5254)
+++ /pjproject/trunk/pjmedia/src/pjmedia/endpoint.c	(revision 5255)
@@ -106,8 +106,8 @@
  * Initialize and get the instance of media endpoint.
  */
-PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
-					 pj_ioqueue_t *ioqueue,
-					 unsigned worker_cnt,
-					 pjmedia_endpt **p_endpt)
+PJ_DEF(pj_status_t) pjmedia_endpt_create2(pj_pool_factory *pf,
+					  pj_ioqueue_t *ioqueue,
+					  unsigned worker_cnt,
+					  pjmedia_endpt **p_endpt)
 {
     pj_pool_t *pool;
@@ -134,8 +134,13 @@
     endpt->has_telephone_event = PJ_TRUE;
 
-    /* Sound */
-    status = pjmedia_aud_subsys_init(pf);
-    if (status != PJ_SUCCESS)
-	goto on_error;
+    /* Initialize audio subsystem.
+     * To avoid pjmedia's dependendy on pjmedia-audiodev, the initialization
+     * (and shutdown) of audio subsystem will be done in the application
+     * level instead, when it calls inline functions pjmedia_endpt_create()
+     * and pjmedia_endpt_destroy().
+     */
+    //status = pjmedia_aud_subsys_init(pf);
+    //if (status != PJ_SUCCESS)
+    //	goto on_error;
 
     /* Init codec manager. */
@@ -189,5 +194,5 @@
 
     pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
-    pjmedia_aud_subsys_shutdown();
+    //pjmedia_aud_subsys_shutdown();
     pj_pool_release(pool);
     return status;
@@ -205,5 +210,5 @@
  * Deinitialize media endpoint.
  */
-PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
+PJ_DEF(pj_status_t) pjmedia_endpt_destroy2 (pjmedia_endpt *endpt)
 {
     exit_cb *ecb;
@@ -220,5 +225,5 @@
 
     pjmedia_codec_mgr_destroy(&endpt->codec_mgr);
-    pjmedia_aud_subsys_shutdown();
+    //pjmedia_aud_subsys_shutdown();
 
     /* Call all registered exit callbacks */
Index: /pjproject/trunk/pjmedia/src/pjmedia/sound_legacy.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sound_legacy.c	(revision 5254)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sound_legacy.c	(revision 5255)
@@ -28,5 +28,4 @@
 
 #include <pjmedia/sound.h>
-#include <pjmedia-audiodev/errno.h>
 #include <pj/assert.h>
 
@@ -50,18 +49,4 @@
 };
 
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    return pjmedia_aud_subsys_init(factory);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    return pjmedia_aud_subsys_shutdown();
-}
-
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
-    return pjmedia_aud_dev_count();
-}
 
 PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
@@ -159,5 +144,5 @@
 
     /* Create sound wrapper */
-    pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(),
+    pool = pj_pool_create(pjmedia_get_aud_subsys()->pf,
 			  "legacy-snd", 512, 512, NULL);
     snd_strm = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
Index: /pjproject/trunk/pjmedia/src/pjmedia/videodev.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/videodev.c	(revision 5255)
+++ /pjproject/trunk/pjmedia/src/pjmedia/videodev.c	(revision 5255)
@@ -0,0 +1,699 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia-videodev/videodev_imp.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+#include <pj/log.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+
+#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
+
+
+#define THIS_FILE   "videodev.c"
+
+#define DEFINE_CAP(name, info)	{name, info}
+
+/* Capability names */
+static struct cap_info
+{
+    const char *name;
+    const char *info;
+} cap_infos[] = 
+{
+    DEFINE_CAP("format",        "Video format"),
+    DEFINE_CAP("scale",         "Input dimension"),
+    DEFINE_CAP("window",        "Window handle"),
+    DEFINE_CAP("resize",        "Renderer resize"),
+    DEFINE_CAP("position",      "Renderer position"),
+    DEFINE_CAP("hide",          "Renderer hide"),
+    DEFINE_CAP("preview",       "Input preview"),
+    DEFINE_CAP("orientation",   "Video orientation"),
+    DEFINE_CAP("switch",        "Switch device"),
+    DEFINE_CAP("wndflags",      "Window flags")
+};
+
+
+/*
+ * The device index seen by application and driver is different. 
+ *
+ * At application level, device index is index to global list of device.
+ * At driver level, device index is index to device list on that particular
+ * factory only.
+ */
+#define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
+#define GET_INDEX(dev_id)	   ((dev_id) & 0xFFFF)
+#define GET_FID(dev_id)		   ((dev_id) >> 16)
+#define DEFAULT_DEV_ID		    0
+
+
+#define MAX_DRIVERS	PJMEDIA_VID_DEV_MAX_DRIVERS
+#define MAX_DEVS	PJMEDIA_VID_DEV_MAX_DEVS
+
+static pjmedia_vid_subsys vid_subsys;
+
+
+/* API: get the video subsystem. */
+PJ_DEF(pjmedia_vid_subsys*) pjmedia_get_vid_subsys(void)
+{
+    return &vid_subsys;
+}
+
+
+/* API: get capability name/info */
+PJ_DEF(const char*) pjmedia_vid_dev_cap_name(pjmedia_vid_dev_cap cap,
+					     const char **p_desc)
+{
+    const char *desc;
+    unsigned i;
+
+    if (p_desc==NULL) p_desc = &desc;
+
+    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
+	if ((1 << i)==cap)
+	    break;
+    }
+
+    if (i==PJ_ARRAY_SIZE(cap_infos)) {
+	*p_desc = "??";
+	return "??";
+    }
+
+    *p_desc = cap_infos[i].info;
+    return cap_infos[i].name;
+}
+
+static pj_status_t get_cap_pointer(const pjmedia_vid_dev_param *param,
+				   pjmedia_vid_dev_cap cap,
+				   void **ptr,
+				   unsigned *size)
+{
+#define FIELD_INFO(name)    *ptr = (void*)&param->name; \
+			    *size = sizeof(param->name)
+
+    switch (cap) {
+    case PJMEDIA_VID_DEV_CAP_FORMAT:
+	FIELD_INFO(fmt);
+	break;
+    case PJMEDIA_VID_DEV_CAP_INPUT_SCALE:
+	FIELD_INFO(disp_size);
+	break;
+    case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW:
+	FIELD_INFO(window);
+	break;
+    case PJMEDIA_VID_DEV_CAP_OUTPUT_RESIZE:
+	FIELD_INFO(disp_size);
+	break;
+    case PJMEDIA_VID_DEV_CAP_OUTPUT_POSITION:
+	FIELD_INFO(window_pos);
+	break;
+    case PJMEDIA_VID_DEV_CAP_OUTPUT_HIDE:
+	FIELD_INFO(window_hide);
+	break;
+    case PJMEDIA_VID_DEV_CAP_INPUT_PREVIEW:
+	FIELD_INFO(native_preview);
+	break;
+    case PJMEDIA_VID_DEV_CAP_ORIENTATION:
+	FIELD_INFO(orient);
+	break;
+    /* The PJMEDIA_VID_DEV_CAP_SWITCH does not have an entry in the
+     * param (it doesn't make sense to open a stream and tell it
+     * to switch immediately).
+     */
+    case PJMEDIA_VID_DEV_CAP_OUTPUT_WINDOW_FLAGS:
+	FIELD_INFO(window_flags);
+	break;
+    default:
+	return PJMEDIA_EVID_INVCAP;
+    }
+
+#undef FIELD_INFO
+
+    return PJ_SUCCESS;
+}
+
+/* API: set cap value to param */
+PJ_DEF(pj_status_t)
+pjmedia_vid_dev_param_set_cap( pjmedia_vid_dev_param *param,
+			       pjmedia_vid_dev_cap cap,
+			       const void *pval)
+{
+    void *cap_ptr;
+    unsigned cap_size;
+    pj_status_t status;
+
+    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_memcpy(cap_ptr, pval, cap_size);
+    param->flags |= cap;
+
+    return PJ_SUCCESS;
+}
+
+/* API: get cap value from param */
+PJ_DEF(pj_status_t)
+pjmedia_vid_dev_param_get_cap( const pjmedia_vid_dev_param *param,
+			       pjmedia_vid_dev_cap cap,
+			       void *pval)
+{
+    void *cap_ptr;
+    unsigned cap_size;
+    pj_status_t status;
+
+    status = get_cap_pointer(param, cap, &cap_ptr, &cap_size);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if ((param->flags & cap) == 0) {
+	pj_bzero(cap_ptr, cap_size);
+	return PJMEDIA_EVID_INVCAP;
+    }
+
+    pj_memcpy(pval, cap_ptr, cap_size);
+    return PJ_SUCCESS;
+}
+
+/* API: init driver */
+PJ_DEF(pj_status_t) pjmedia_vid_driver_init(unsigned drv_idx,
+					    pj_bool_t refresh)
+{
+    pjmedia_vid_driver *drv = &vid_subsys.drv[drv_idx];
+    pjmedia_vid_dev_factory *f;
+    unsigned i, dev_cnt;
+    pj_status_t status;
+
+    if (!refresh) {
+        /* Create the factory */
+        f = (*drv->create)(vid_subsys.pf);
+        if (!f)
+            return PJ_EUNKNOWN;
+
+        /* Call factory->init() */
+        status = f->op->init(f);
+        if (status != PJ_SUCCESS) {
+            f->op->destroy(f);
+            return status;
+        }
+    } else {
+	f = drv->f;
+    }
+
+    /* Get number of devices */
+    dev_cnt = f->op->get_dev_count(f);
+    if (dev_cnt + vid_subsys.dev_cnt > MAX_DEVS) {
+	PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
+			      " there are too many devices",
+			      vid_subsys.dev_cnt + dev_cnt - MAX_DEVS));
+	dev_cnt = MAX_DEVS - vid_subsys.dev_cnt;
+    }
+
+    /* enabling this will cause pjsua-lib initialization to fail when there
+     * is no video device installed in the system, even when pjsua has been
+     * run with --null-video
+     *
+    if (dev_cnt == 0) {
+	f->op->destroy(f);
+	return PJMEDIA_EVID_NODEV;
+    }
+    */
+
+    /* Fill in default devices */
+    drv->rend_dev_idx = drv->cap_dev_idx = -1;
+    for (i=0; i<dev_cnt; ++i) {
+	pjmedia_vid_dev_info info;
+
+	status = f->op->get_dev_info(f, i, &info);
+	if (status != PJ_SUCCESS) {
+	    f->op->destroy(f);
+	    return status;
+	}
+
+	if (drv->name[0]=='\0') {
+	    /* Set driver name */
+	    pj_ansi_strncpy(drv->name, info.driver, sizeof(drv->name));
+	    drv->name[sizeof(drv->name)-1] = '\0';
+	}
+
+	if (drv->rend_dev_idx < 0 && (info.dir & PJMEDIA_DIR_RENDER)) {
+	    /* Set default render device */
+	    drv->rend_dev_idx = i;
+	}
+	if (drv->cap_dev_idx < 0 && (info.dir & PJMEDIA_DIR_CAPTURE)) {
+	    /* Set default capture device */
+	    drv->cap_dev_idx = i;
+	}
+
+        if (drv->rend_dev_idx >= 0 && drv->cap_dev_idx >= 0) {
+	    /* Done. */
+	    break;
+	}
+    }
+
+    /* Register the factory */
+    drv->f = f;
+    drv->f->sys.drv_idx = drv_idx;
+    drv->start_idx = vid_subsys.dev_cnt;
+    drv->dev_cnt = dev_cnt;
+
+    /* Register devices to global list */
+    for (i=0; i<dev_cnt; ++i) {
+	vid_subsys.dev_list[vid_subsys.dev_cnt++] = MAKE_DEV_ID(drv_idx, i);
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: deinit driver */
+PJ_DEF(void) pjmedia_vid_driver_deinit(unsigned drv_idx)
+{
+    pjmedia_vid_driver *drv = &vid_subsys.drv[drv_idx];
+
+    if (drv->f) {
+	drv->f->op->destroy(drv->f);
+	drv->f = NULL;
+    }
+
+    drv->dev_cnt = 0;
+    drv->rend_dev_idx = drv->cap_dev_idx = -1;
+}
+
+
+/* API: Refresh the list of video devices installed in the system. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_refresh(void)
+{
+    unsigned i;
+    
+    vid_subsys.dev_cnt = 0;
+    for (i=0; i<vid_subsys.drv_cnt; ++i) {
+	pjmedia_vid_driver *drv = &vid_subsys.drv[i];
+	
+	if (drv->f && drv->f->op->refresh) {
+	    pj_status_t status = drv->f->op->refresh(drv->f);
+	    if (status != PJ_SUCCESS) {
+		PJ_PERROR(4, (THIS_FILE, status, "Unable to refresh device "
+						 "list for %s", drv->name));
+	    }
+	}
+	pjmedia_vid_driver_init(i, PJ_TRUE);
+    }
+    return PJ_SUCCESS;
+}
+
+/* API: Get the number of video devices installed in the system. */
+PJ_DEF(unsigned) pjmedia_vid_dev_count(void)
+{
+    return vid_subsys.dev_cnt;
+}
+
+/* Internal: convert local index to global device index */
+static pj_status_t make_global_index(unsigned drv_idx, 
+				     pjmedia_vid_dev_index *id)
+{
+    if (*id < 0) {
+	return PJ_SUCCESS;
+    }
+
+    /* Check that factory still exists */
+    PJ_ASSERT_RETURN(vid_subsys.drv[drv_idx].f, PJ_EBUG);
+
+    /* Check that device index is valid */
+    PJ_ASSERT_RETURN(*id>=0 && *id<(int)vid_subsys.drv[drv_idx].dev_cnt, 
+		     PJ_EBUG);
+
+    *id += vid_subsys.drv[drv_idx].start_idx;
+    return PJ_SUCCESS;
+}
+
+/* Internal: lookup device id */
+static pj_status_t lookup_dev(pjmedia_vid_dev_index id,
+			      pjmedia_vid_dev_factory **p_f,
+			      unsigned *p_local_index)
+{
+    int f_id, index;
+
+    if (id < 0) {
+	unsigned i;
+
+	if (id <= PJMEDIA_VID_INVALID_DEV)
+	    return PJMEDIA_EVID_INVDEV;
+
+	for (i=0; i<vid_subsys.drv_cnt; ++i) {
+	    pjmedia_vid_driver *drv = &vid_subsys.drv[i];
+	    if (id==PJMEDIA_VID_DEFAULT_CAPTURE_DEV && 
+		drv->cap_dev_idx >= 0) 
+	    {
+		id = drv->cap_dev_idx;
+		make_global_index(i, &id);
+		break;
+	    } else if (id==PJMEDIA_VID_DEFAULT_RENDER_DEV && 
+		drv->rend_dev_idx >= 0) 
+	    {
+		id = drv->rend_dev_idx;
+		make_global_index(i, &id);
+		break;
+	    }
+	}
+
+	if (id < 0) {
+	    return PJMEDIA_EVID_NODEFDEV;
+	}
+    }
+
+    f_id = GET_FID(vid_subsys.dev_list[id]);
+    index = GET_INDEX(vid_subsys.dev_list[id]);
+
+    if (f_id < 0 || f_id >= (int)vid_subsys.drv_cnt)
+	return PJMEDIA_EVID_INVDEV;
+
+    if (index < 0 || index >= (int)vid_subsys.drv[f_id].dev_cnt)
+	return PJMEDIA_EVID_INVDEV;
+
+    *p_f = vid_subsys.drv[f_id].f;
+    *p_local_index = (unsigned)index;
+
+    return PJ_SUCCESS;
+
+}
+
+/* API: lookup device id */
+PJ_DEF(pj_status_t)
+pjmedia_vid_dev_get_local_index(pjmedia_vid_dev_index id,
+                                pjmedia_vid_dev_factory **p_f,
+                                unsigned *p_local_index)
+{
+    return lookup_dev(id, p_f, p_local_index);
+}
+
+/* API: from factory and local index, get global index */
+PJ_DEF(pj_status_t)
+pjmedia_vid_dev_get_global_index(const pjmedia_vid_dev_factory *f,
+                                 unsigned local_idx,
+                                 pjmedia_vid_dev_index *pid)
+{
+    PJ_ASSERT_RETURN(f->sys.drv_idx >= 0 && f->sys.drv_idx < MAX_DRIVERS,
+                     PJ_EINVALIDOP);
+    *pid = local_idx;
+    return make_global_index(f->sys.drv_idx, pid);
+}
+
+/* API: Get device information. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_get_info(pjmedia_vid_dev_index id,
+					     pjmedia_vid_dev_info *info)
+{
+    pjmedia_vid_dev_factory *f;
+    unsigned index;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(info, PJ_EINVAL);
+    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
+
+    if (id <= PJMEDIA_VID_INVALID_DEV)
+	return PJMEDIA_EVID_INVDEV;
+
+    status = lookup_dev(id, &f, &index);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = f->op->get_dev_info(f, index, info);
+
+    /* Make sure device ID is the real ID (not PJMEDIA_VID_DEFAULT_*_DEV) */
+    info->id = index;
+    make_global_index(f->sys.drv_idx, &info->id);
+
+    return status;
+}
+
+/* API: find device */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_lookup( const char *drv_name,
+					    const char *dev_name,
+					    pjmedia_vid_dev_index *id)
+{
+    pjmedia_vid_dev_factory *f = NULL;
+    unsigned drv_idx, dev_idx;
+
+    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
+    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
+
+    for (drv_idx=0; drv_idx<vid_subsys.drv_cnt; ++drv_idx) {
+	if (!pj_ansi_stricmp(drv_name, vid_subsys.drv[drv_idx].name))
+	{
+	    f = vid_subsys.drv[drv_idx].f;
+	    break;
+	}
+    }
+
+    if (!f)
+	return PJ_ENOTFOUND;
+
+    for (dev_idx=0; dev_idx<vid_subsys.drv[drv_idx].dev_cnt; ++dev_idx)
+    {
+	pjmedia_vid_dev_info info;
+	pj_status_t status;
+
+	status = f->op->get_dev_info(f, dev_idx, &info);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	if (!pj_ansi_stricmp(dev_name, info.name))
+	    break;
+    }
+
+    if (dev_idx==vid_subsys.drv[drv_idx].dev_cnt)
+	return PJ_ENOTFOUND;
+
+    *id = dev_idx;
+    make_global_index(drv_idx, id);
+
+    return PJ_SUCCESS;
+}
+
+/* API: Initialize the video device parameters with default values for the
+ * specified device.
+ */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_default_param(pj_pool_t *pool,
+                                                  pjmedia_vid_dev_index id,
+						  pjmedia_vid_dev_param *param)
+{
+    pjmedia_vid_dev_factory *f;
+    unsigned index;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(param, PJ_EINVAL);
+    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
+
+    if (id <= PJMEDIA_VID_INVALID_DEV)
+	return PJMEDIA_EVID_INVDEV;
+
+    status = lookup_dev(id, &f, &index);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = f->op->default_param(pool, f, index, param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Normalize device IDs */
+    make_global_index(f->sys.drv_idx, &param->cap_id);
+    make_global_index(f->sys.drv_idx, &param->rend_id);
+
+    return PJ_SUCCESS;
+}
+
+/* API: Open video stream object using the specified parameters. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_create(
+					pjmedia_vid_dev_param *prm,
+					const pjmedia_vid_dev_cb *cb,
+					void *user_data,
+					pjmedia_vid_dev_stream **p_vid_strm)
+{
+    pjmedia_vid_dev_factory *cap_f=NULL, *rend_f=NULL, *f=NULL;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(prm && prm->dir && p_vid_strm, PJ_EINVAL);
+    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
+    PJ_ASSERT_RETURN(prm->dir==PJMEDIA_DIR_CAPTURE ||
+		     prm->dir==PJMEDIA_DIR_RENDER ||
+		     prm->dir==PJMEDIA_DIR_CAPTURE_RENDER,
+		     PJ_EINVAL);
+
+    /* Normalize cap_id */
+    if (prm->dir & PJMEDIA_DIR_CAPTURE) {
+	unsigned index;
+
+	if (prm->cap_id < 0)
+	    prm->cap_id = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+
+	status = lookup_dev(prm->cap_id, &cap_f, &index);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	prm->cap_id = index;
+	f = cap_f;
+    }
+
+    /* Normalize rend_id */
+    if (prm->dir & PJMEDIA_DIR_RENDER) {
+	unsigned index;
+
+	if (prm->rend_id < 0)
+	    prm->rend_id = PJMEDIA_VID_DEFAULT_RENDER_DEV;
+
+	status = lookup_dev(prm->rend_id, &rend_f, &index);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	prm->rend_id = index;
+	f = rend_f;
+    }
+
+    PJ_ASSERT_RETURN(f != NULL, PJ_EBUG);
+
+    /* For now, cap_id and rend_id must belong to the same factory */
+    PJ_ASSERT_RETURN((prm->dir != PJMEDIA_DIR_CAPTURE_RENDER) ||
+		     (cap_f == rend_f),
+		     PJMEDIA_EVID_INVDEV);
+
+    /* Create the stream */
+    status = f->op->create_stream(f, prm, cb,
+				  user_data, p_vid_strm);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Assign factory id to the stream */
+    (*p_vid_strm)->sys.drv_idx = f->sys.drv_idx;
+    return PJ_SUCCESS;
+}
+
+/* API: Get the running parameters for the specified video stream. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_param(
+					    pjmedia_vid_dev_stream *strm,
+					    pjmedia_vid_dev_param *param)
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(strm && param, PJ_EINVAL);
+    PJ_ASSERT_RETURN(vid_subsys.pf, PJMEDIA_EVID_INIT);
+
+    status = strm->op->get_param(strm, param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Normalize device id's */
+    make_global_index(strm->sys.drv_idx, &param->cap_id);
+    make_global_index(strm->sys.drv_idx, &param->rend_id);
+
+    return PJ_SUCCESS;
+}
+
+/* API: Get the value of a specific capability of the video stream. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_cap(
+					    pjmedia_vid_dev_stream *strm,
+					    pjmedia_vid_dev_cap cap,
+					    void *value)
+{
+    return strm->op->get_cap(strm, cap, value);
+}
+
+/* API: Set the value of a specific capability of the video stream. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_set_cap(
+					    pjmedia_vid_dev_stream *strm,
+					    pjmedia_vid_dev_cap cap,
+					    const void *value)
+{
+    /* For fast switching, device global index needs to be converted to
+     * local index before forwarding the request to the device stream.
+     */
+    if (cap == PJMEDIA_VID_DEV_CAP_SWITCH) {
+	pjmedia_vid_dev_factory *f;
+	unsigned local_idx;
+	pj_status_t status;
+	pjmedia_vid_dev_switch_param p = *(pjmedia_vid_dev_switch_param*)value;
+
+	status = lookup_dev(p.target_id, &f, &local_idx);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* Make sure that current & target devices share the same factory */
+	if (f->sys.drv_idx != strm->sys.drv_idx)
+	    return PJMEDIA_EVID_INVDEV;
+
+	p.target_id = local_idx;
+	return strm->op->set_cap(strm, cap, &p);
+    }
+
+    return strm->op->set_cap(strm, cap, value);
+}
+
+/* API: Start the stream. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_start(pjmedia_vid_dev_stream *strm)
+{
+    pj_status_t status;
+
+    if (pjmedia_vid_dev_stream_is_running(strm))
+	return PJ_SUCCESS;
+
+    status = strm->op->start(strm);
+    if (status == PJ_SUCCESS)
+	strm->sys.is_running = PJ_TRUE;
+    return status;
+}
+
+/* API: has it been started? */
+PJ_DEF(pj_bool_t)
+pjmedia_vid_dev_stream_is_running(pjmedia_vid_dev_stream *strm)
+{
+    return strm->sys.is_running;
+}
+
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_get_frame(
+					    pjmedia_vid_dev_stream *strm,
+					    pjmedia_frame *frame)
+{
+    pj_assert(strm->op->get_frame);
+    return strm->op->get_frame(strm, frame);
+}
+
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_put_frame(
+					    pjmedia_vid_dev_stream *strm,
+                                            const pjmedia_frame *frame)
+{
+    pj_assert(strm->op->put_frame);
+    return strm->op->put_frame(strm, frame);
+}
+
+/* API: Stop the stream. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_stop(pjmedia_vid_dev_stream *strm)
+{
+    strm->sys.is_running = PJ_FALSE;
+    return strm->op->stop(strm);
+}
+
+/* API: Destroy the stream. */
+PJ_DEF(pj_status_t) pjmedia_vid_dev_stream_destroy(
+						pjmedia_vid_dev_stream *strm)
+{
+    strm->sys.is_running = PJ_FALSE;
+    return strm->op->destroy(strm);
+}
+
+
+#endif /* PJMEDIA_HAS_VIDEO */
