From 70231deed2aa68e30657db5434cfdbcd320373c7 Mon Sep 17 00:00:00 2001 From: Liong Sauw Ming Date: Thu, 10 Mar 2016 05:02:07 +0000 Subject: Fixed #1907: Remove pjmedia* circular dependency git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5255 74dad513-b988-da41-8d7b-12977e46ad98 --- pjmedia/build/Makefile | 20 +- pjmedia/include/pjmedia-audiodev/audiodev.h | 626 +-------------------- pjmedia/include/pjmedia-videodev/videodev.h | 725 +----------------------- pjmedia/include/pjmedia/audiodev.h | 728 ++++++++++++++++++++++++ pjmedia/include/pjmedia/endpoint.h | 63 ++- pjmedia/include/pjmedia/sound.h | 17 +- pjmedia/include/pjmedia/videodev.h | 824 ++++++++++++++++++++++++++++ pjmedia/src/pjmedia-audiodev/audiodev.c | 703 ++---------------------- pjmedia/src/pjmedia-videodev/videodev.c | 757 ++----------------------- pjmedia/src/pjmedia/audiodev.c | 628 +++++++++++++++++++++ pjmedia/src/pjmedia/endpoint.c | 27 +- pjmedia/src/pjmedia/sound_legacy.c | 17 +- pjmedia/src/pjmedia/videodev.c | 699 +++++++++++++++++++++++ 13 files changed, 3070 insertions(+), 2764 deletions(-) create mode 100644 pjmedia/include/pjmedia/audiodev.h create mode 100644 pjmedia/include/pjmedia/videodev.h create mode 100644 pjmedia/src/pjmedia/audiodev.c create mode 100644 pjmedia/src/pjmedia/videodev.c diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile index 2a4af87d..53faa2dc 100644 --- a/pjmedia/build/Makefile +++ b/pjmedia/build/Makefile @@ -75,13 +75,11 @@ export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ types.o vid_codec.o vid_codec_util.o \ 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) \ $(_LDFLAGS) @@ -97,7 +95,8 @@ export PJMEDIA_AUDIODEV_OBJS += audiodev.o audiotest.o errno.o \ android_jni_dev.o opensl_dev.o 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) @@ -105,12 +104,13 @@ export PJMEDIA_AUDIODEV_LDFLAGS += $(PJLIB_LDLIB) \ # Defines for building PJMEDIA-VIDEODEV library # 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) @@ -211,7 +211,7 @@ distclean: realclean 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)/$@) pjmedia-codec: $(PJMEDIA_CODEC_LIB) @@ -221,12 +221,12 @@ $(PJMEDIA_CODEC_LIB) $(PJMEDIA_CODEC_SONAME): $(PJMEDIA_LIB) $(PJMEDIA_SONAME) 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)/$@) pjsdp: $(PJSDP_LIB) diff --git a/pjmedia/include/pjmedia-audiodev/audiodev.h b/pjmedia/include/pjmedia-audiodev/audiodev.h index b5e144f2..106a0328 100644 --- a/pjmedia/include/pjmedia-audiodev/audiodev.h +++ b/pjmedia/include/pjmedia-audiodev/audiodev.h @@ -22,478 +22,21 @@ /** * @file audiodev.h - * @brief Audio device API. + * @brief Audio subsystem API. */ -#include -#include -#include -#include -#include #include +#include PJ_BEGIN_DECL /** - * @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); /** * Initialize the audio subsystem. This will register all supported audio @@ -557,167 +100,6 @@ PJ_DECL(pj_status_t) pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf); -/** - * 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); - - /** * @} */ diff --git a/pjmedia/include/pjmedia-videodev/videodev.h b/pjmedia/include/pjmedia-videodev/videodev.h index 21fba158..66407243 100644 --- a/pjmedia/include/pjmedia-videodev/videodev.h +++ b/pjmedia/include/pjmedia-videodev/videodev.h @@ -23,517 +23,18 @@ * @file videodev.h * @brief Video device API. */ -#include -#include -#include -#include -#include -#include +#include PJ_BEGIN_DECL /** - * @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); /** * Initialize the video device subsystem. This will register all supported @@ -609,226 +110,6 @@ pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr vdf, pjmedia_vid_dev_factory *factory); -/** - * 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); - - /** * @} */ diff --git a/pjmedia/include/pjmedia/audiodev.h b/pjmedia/include/pjmedia/audiodev.h new file mode 100644 index 00000000..473c9fd1 --- /dev/null +++ b/pjmedia/include/pjmedia/audiodev.h @@ -0,0 +1,728 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 +#include +#include +#include +#include +#include + + +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__ */ + diff --git a/pjmedia/include/pjmedia/endpoint.h b/pjmedia/include/pjmedia/endpoint.h index f300571b..42108c1e 100644 --- a/pjmedia/include/pjmedia/endpoint.h +++ b/pjmedia/include/pjmedia/endpoint.h @@ -40,6 +40,7 @@ #include #include #include +#include PJ_BEGIN_DECL @@ -81,11 +82,51 @@ typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt); * * @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, pjmedia_endpt **p_endpt); +/** + * 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. * @@ -93,7 +134,25 @@ PJ_DECL(pj_status_t) pjmedia_endpt_create( pj_pool_factory *pf, * * @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; +} /** * Change the value of a flag. diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h index 3bedb08f..73f379b6 100644 --- a/pjmedia/include/pjmedia/sound.h +++ b/pjmedia/include/pjmedia/sound.h @@ -140,8 +140,13 @@ typedef pj_status_t (*pjmedia_snd_rec_cb)(/* in */ void *user_data, * * @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); +} /** * Get the number of devices detected by the library. @@ -323,7 +328,13 @@ PJ_DECL(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream); * * @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(); +} diff --git a/pjmedia/include/pjmedia/videodev.h b/pjmedia/include/pjmedia/videodev.h new file mode 100644 index 00000000..37447006 --- /dev/null +++ b/pjmedia/include/pjmedia/videodev.h @@ -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 +#include +#include +#include +#include +#include + + +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__ */ diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c index f747373e..e28bf318 100644 --- a/pjmedia/src/pjmedia-audiodev/audiodev.c +++ b/pjmedia/src/pjmedia-audiodev/audiodev.c @@ -19,51 +19,9 @@ */ #include #include -#include -#include -#include -#include #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 - /* extern functions to create factories */ #if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO @@ -114,285 +72,18 @@ pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf); pjmedia_aud_dev_factory* pjmedia_null_audio_factory(pj_pool_factory *pf); #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; iname; \ - *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; iop->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; if) { - 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. */ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf) { 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; } @@ -403,58 +94,58 @@ PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf) pj_assert(status == PJ_SUCCESS); /* 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; idrv_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; } /* API: register an audio device factory to the audio subsystem. */ @@ -462,16 +153,17 @@ PJ_DEF(pj_status_t) pjmedia_aud_register_factory(pjmedia_aud_dev_factory_create_func_ptr adf) { pj_status_t status; + pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); - if (aud_subsys.init_count == 0) + 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); } return status; @@ -482,20 +174,21 @@ PJ_DEF(pj_status_t) pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf) { unsigned i, j; + pjmedia_aud_subsys *aud_subsys = pjmedia_get_aud_subsys(); - if (aud_subsys.init_count == 0) + if (aud_subsys->init_count == 0) return PJMEDIA_EAUD_INIT; - for (i=0; idrv_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; } } @@ -506,342 +199,30 @@ pjmedia_aud_unregister_factory(pjmedia_aud_dev_factory_create_func_ptr adf) /* API: get the pool factory registered to the audio subsystem. */ 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; } /* API: Shutdown the audio subsystem. */ PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void) { 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) { - return PJ_SUCCESS; - } - --aud_subsys.init_count; - - if (aud_subsys.init_count == 0) { - for (i=0; if && 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) { + if (aud_subsys->init_count == 0) { return PJ_SUCCESS; } + --aud_subsys->init_count; - /* 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; idev_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; + if (aud_subsys->init_count == 0) { + for (i=0; idrv_cnt; ++i) { + pjmedia_aud_driver_deinit(i); } - } - - 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_idxop->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, ¶m->rec_id); - make_global_index(f->sys.drv_idx, ¶m->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(¶m, 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; + aud_subsys->pf = NULL; } - - /* 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, ¶m, 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, ¶m->rec_id); - make_global_index(strm->sys.drv_idx, ¶m->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); -} - - diff --git a/pjmedia/src/pjmedia-videodev/videodev.c b/pjmedia/src/pjmedia-videodev/videodev.c index 8558588d..1d560975 100644 --- a/pjmedia/src/pjmedia-videodev/videodev.c +++ b/pjmedia/src/pjmedia-videodev/videodev.c @@ -18,10 +18,6 @@ */ #include #include -#include -#include -#include -#include #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) @@ -29,40 +25,6 @@ #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 - /* extern functions to create factories */ #if PJMEDIA_VIDEO_DEV_HAS_NULL_VIDEO @@ -109,262 +71,17 @@ pjmedia_vid_dev_factory* pjmedia_and_factory(pj_pool_factory *pf); #define MAX_DEVS PJMEDIA_VID_DEV_MAX_DEVS -/* 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; iname; \ - *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; iop->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; if) { - 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) { 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; } @@ -374,52 +91,52 @@ PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_init(pj_pool_factory *pf) &pjmedia_videodev_strerror); /* 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 /* Better put colorbar at the last, so the default capturer will be * 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; idrv_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; } /* API: register a video device factory to the video device subsystem. */ @@ -429,12 +146,13 @@ pjmedia_vid_register_factory(pjmedia_vid_dev_factory_create_func_ptr adf, { pj_bool_t refresh = PJ_FALSE; pj_status_t status; + pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys(); - if (vid_subsys.init_count == 0) + 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) { /* Call factory->init() */ @@ -446,11 +164,11 @@ pjmedia_vid_register_factory(pjmedia_vid_dev_factory_create_func_ptr adf, refresh = PJ_TRUE; } - 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); } return status; @@ -462,20 +180,21 @@ pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr adf, pjmedia_vid_dev_factory *factory) { unsigned i, j; + pjmedia_vid_subsys *vid_subsys = pjmedia_get_vid_subsys(); - if (vid_subsys.init_count == 0) + if (vid_subsys->init_count == 0) return PJMEDIA_EVID_INIT; - for (i=0; idrv_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; } @@ -487,429 +206,33 @@ pjmedia_vid_unregister_factory(pjmedia_vid_dev_factory_create_func_ptr adf, /* API: get the pool factory registered to the video device subsystem. */ 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; } /* API: Shutdown the video device subsystem. */ PJ_DEF(pj_status_t) pjmedia_vid_dev_subsys_shutdown(void) { 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; + --vid_subsys->init_count; - if (vid_subsys.init_count == 0) { - for (i=0; iinit_count == 0) { + for (i=0; idrv_cnt; ++i) { + pjmedia_vid_driver_deinit(i); } - 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; if && 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; icap_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_idxop->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, ¶m->cap_id); - make_global_index(f->sys.drv_idx, ¶m->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; + vid_subsys->pf = NULL; } - - /* 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, ¶m->cap_id); - make_global_index(strm->sys.drv_idx, ¶m->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 */ diff --git a/pjmedia/src/pjmedia/audiodev.c b/pjmedia/src/pjmedia/audiodev.c new file mode 100644 index 00000000..398a4042 --- /dev/null +++ b/pjmedia/src/pjmedia/audiodev.c @@ -0,0 +1,628 @@ +/* $Id$ */ +/* + * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * 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 +#include +#include +#include +#include +#include + +#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; iop->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; if) { + 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; iname; \ + *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; if && 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; idev_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_idxop->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, ¶m->rec_id); + make_global_index(f->sys.drv_idx, ¶m->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(¶m, 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, ¶m, 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, ¶m->rec_id); + make_global_index(strm->sys.drv_idx, ¶m->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); +} + + diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c index 650c71d8..82d7d568 100644 --- a/pjmedia/src/pjmedia/endpoint.c +++ b/pjmedia/src/pjmedia/endpoint.c @@ -105,10 +105,10 @@ struct pjmedia_endpt /** * 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; pjmedia_endpt *endpt; @@ -133,10 +133,15 @@ PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf, endpt->thread_cnt = worker_cnt; 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. */ status = pjmedia_codec_mgr_init(&endpt->codec_mgr, endpt->pf); @@ -188,7 +193,7 @@ on_error: pj_ioqueue_destroy(endpt->ioqueue); pjmedia_codec_mgr_destroy(&endpt->codec_mgr); - pjmedia_aud_subsys_shutdown(); + //pjmedia_aud_subsys_shutdown(); pj_pool_release(pool); return status; } @@ -204,7 +209,7 @@ PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt) /** * 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; @@ -219,7 +224,7 @@ PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt) endpt->pf = NULL; pjmedia_codec_mgr_destroy(&endpt->codec_mgr); - pjmedia_aud_subsys_shutdown(); + //pjmedia_aud_subsys_shutdown(); /* Call all registered exit callbacks */ ecb = endpt->exit_cb_list.next; diff --git a/pjmedia/src/pjmedia/sound_legacy.c b/pjmedia/src/pjmedia/sound_legacy.c index d5bcf3dc..ee9dd027 100644 --- a/pjmedia/src/pjmedia/sound_legacy.c +++ b/pjmedia/src/pjmedia/sound_legacy.c @@ -27,7 +27,6 @@ */ #include -#include #include #if PJMEDIA_HAS_LEGACY_SOUND_API @@ -49,20 +48,6 @@ struct pjmedia_snd_stream void *user_user_data; }; -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) { @@ -158,7 +143,7 @@ static pj_status_t open_stream( pjmedia_dir dir, } /* 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); snd_strm->pool = pool; diff --git a/pjmedia/src/pjmedia/videodev.c b/pjmedia/src/pjmedia/videodev.c new file mode 100644 index 00000000..84d26069 --- /dev/null +++ b/pjmedia/src/pjmedia/videodev.c @@ -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 +#include +#include +#include +#include +#include + + +#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; iname; \ + *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; iop->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; if) { + 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; if && 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; icap_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_idxop->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, ¶m->cap_id); + make_global_index(f->sys.drv_idx, ¶m->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, ¶m->cap_id); + make_global_index(strm->sys.drv_idx, ¶m->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 */ -- cgit v1.2.3