Updated libraries and applications to use the new Audio Device API
git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/aps-direct@2468 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp
index 5a935be..db23940 100644
--- a/pjmedia/build/pjmedia.dsp
+++ b/pjmedia/build/pjmedia.dsp
@@ -121,10 +121,6 @@
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\dsound.c
-# End Source File
-# Begin Source File
-
SOURCE=..\src\pjmedia\echo_common.c
# End Source File
# Begin Source File
@@ -177,14 +173,6 @@
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\nullsound.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjmedia\pasound.c
-# End Source File
-# Begin Source File
-
SOURCE=..\src\pjmedia\plc_common.c
# End Source File
# Begin Source File
@@ -297,10 +285,6 @@
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\wmme_sound.c
-# End Source File
-# Begin Source File
-
SOURCE=..\src\pjmedia\wsola.c
# End Source File
# End Group
diff --git a/pjmedia/build/pjmedia_audiodev.dsp b/pjmedia/build/pjmedia_audiodev.dsp
index 305a838..44e632c 100644
--- a/pjmedia/build/pjmedia_audiodev.dsp
+++ b/pjmedia/build/pjmedia_audiodev.dsp
@@ -101,6 +101,16 @@
# End Source File
# Begin Source File
+SOURCE="..\src\pjmedia-audiodev\symb_aps_dev.cpp"
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-audiodev\symb_mda_dev.cpp"
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
SOURCE="..\src\pjmedia-audiodev\wmme_dev.c"
# End Source File
# End Group
diff --git a/pjmedia/include/pjmedia-audiodev/audiodev.h b/pjmedia/include/pjmedia-audiodev/audiodev.h
index 2d72e09..e051f2f 100644
--- a/pjmedia/include/pjmedia-audiodev/audiodev.h
+++ b/pjmedia/include/pjmedia-audiodev/audiodev.h
@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __AUDIODEV_H__
-#define __AUDIODEV_H__
+#ifndef __PJMEDIA_AUDIODEV_AUDIODEV_H__
+#define __PJMEDIA_AUDIODEV_AUDIODEV_H__
/**
* @file audiodev.h
@@ -51,11 +51,21 @@
* @{
*/
-/** Device identifier */
-typedef pj_int32_t pjmedia_aud_dev_id;
+/**
+ * Type for device index.
+ */
+typedef pj_int32_t pjmedia_aud_dev_index;
-/** Constant to denote default ID */
-#define PJMEDIA_AUD_DEV_DEFAULT_ID (-1)
+/**
+ * Constant to denote default device
+ */
+#define PJMEDIA_AUD_DEV_DEFAULT (-1)
+
+/**
+ * Type for device unique identifier. The unique device ID can be used to save
+ * a reference to a particular device across software reboots.
+ */
+typedef pj_uint32_t pjmedia_aud_dev_uid;
/**
@@ -66,7 +76,7 @@
* 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_dev_param
+ * 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
@@ -117,14 +127,14 @@
* The value of this capability is an unsigned integer representing
* the audio volume in percent.
*/
- PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_VOLUME = 32,
+ 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_VOLUME = 64,
+ PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64,
/**
* Support for audio input routing. The value of this capability is an
@@ -141,7 +151,7 @@
/**
* The audio device has echo cancellation feature. The value of this
- * capability is an integer containing boolean PJ_TRUE or PJ_FALSE.
+ * capability is a pj_bool_t containing boolean PJ_TRUE or PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_EC = 512,
@@ -154,21 +164,21 @@
/**
* The audio device has voice activity detection feature. The value
- * of this capability is an integer containing boolean PJ_TRUE or
+ * 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 an integer containing boolean PJ_TRUE or
+ * 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 an integer containing boolean PJ_TRUE or
+ * of this capability is a pj_bool_t containing boolean PJ_TRUE or
* PJ_FALSE.
*/
PJMEDIA_AUD_DEV_CAP_PLC = 8192
@@ -225,7 +235,7 @@
/**
* The underlying driver name
*/
- char driver[128];
+ char driver[32];
/**
* Device capabilities, as bitmask combination of #pjmedia_aud_dev_cap.
@@ -289,9 +299,9 @@
pjmedia_frame *frame);
/**
- * This structure specifies the parameters to open the audio device stream.
+ * This structure specifies the parameters to open the audio stream.
*/
-typedef struct pjmedia_aud_dev_param
+typedef struct pjmedia_aud_param
{
/**
* The audio direction. This setting is mandatory.
@@ -302,13 +312,13 @@
* The audio recorder device ID. This setting is mandatory if the audio
* direction includes input/capture direction.
*/
- pjmedia_aud_dev_id rec_id;
+ 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_id play_id;
+ pjmedia_aud_dev_index play_id;
/**
* Clock rate/sampling rate. This setting is mandatory.
@@ -386,7 +396,7 @@
*/
pj_bool_t cng_enabled;
-} pjmedia_aud_dev_param;
+} pjmedia_aud_param;
/** Forward declaration for pjmedia_aud_stream */
@@ -431,6 +441,19 @@
/**
+ * 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);
+
+
+/**
* Get the number of sound devices installed in the system.
*
* @return The number of sound devices installed in the system.
@@ -439,17 +462,6 @@
/**
- * Enumerate device ID's.
- *
- * @param max_count Maximum number of device id's to retrieve.
- * @param ids Array to receive the device id's.
- *
- * @return The actual number of device id's filled in.
- */
-PJ_DECL(unsigned) pjmedia_aud_dev_enum(unsigned max_count,
- pjmedia_aud_dev_id ids[]);
-
-/**
* Get device information.
*
* @param id The audio device ID.
@@ -459,11 +471,24 @@
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
-PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id,
+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.
+ *
+ * @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.
*
@@ -474,8 +499,8 @@
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
-PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_id id,
- pjmedia_aud_dev_param *param);
+PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
+ pjmedia_aud_param *param);
/**
@@ -492,11 +517,11 @@
* @return PJ_SUCCESS on successful operation or the appropriate
* error code.
*/
-PJ_DECL(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_dev_param *param,
+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_aud_strm);
+ pjmedia_aud_stream **p_strm);
/**
* Get the running parameters for the specified audio stream.
@@ -509,7 +534,7 @@
* error code.
*/
PJ_DECL(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
/**
* Get the value of a specific capability of the audio stream.
@@ -580,6 +605,9 @@
/* Device not ready */
#define PJMEDIA_EAUD_NOTREADY -1
+/* Invalid audio capability or audio capability not supported */
+#define PJMEDIA_EAUD_INVCAP -1
+
/* Unknown system error */
#define PJMEDIA_EAUD_SYSERR -1
@@ -591,5 +619,5 @@
PJ_END_DECL
-#endif /* __AUDIODEV_H__ */
+#endif /* __PJMEDIA_AUDIODEV_AUDIODEV_H__ */
diff --git a/pjmedia/include/pjmedia-audiodev/audiodev_imp.h b/pjmedia/include/pjmedia-audiodev/audiodev_imp.h
index 7251e90..a05b34c 100644
--- a/pjmedia/include/pjmedia-audiodev/audiodev_imp.h
+++ b/pjmedia/include/pjmedia-audiodev/audiodev_imp.h
@@ -79,14 +79,14 @@
*/
pj_status_t (*default_param)(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
/**
* Open the audio device and create audio stream. See
* #pjmedia_aud_stream_create()
*/
pj_status_t (*create_stream)(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
@@ -119,7 +119,7 @@
* See #pjmedia_aud_stream_get_param()
*/
pj_status_t (*get_param)(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
/**
* See #pjmedia_aud_stream_get_cap()
@@ -158,8 +158,8 @@
*/
struct pjmedia_aud_stream
{
- /** Factory */
- pjmedia_aud_dev_factory *factory;
+ /** Factory id (internal) */
+ unsigned factory_id;
/** Operations */
pjmedia_aud_stream_op *op;
diff --git a/pjmedia/include/pjmedia-audiodev/audiotest.h b/pjmedia/include/pjmedia-audiodev/audiotest.h
index e247078..16deec7 100644
--- a/pjmedia/include/pjmedia-audiodev/audiotest.h
+++ b/pjmedia/include/pjmedia-audiodev/audiotest.h
@@ -17,8 +17,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __AUDIOTEST_H__
-#define __AUDIOTEST_H__
+#ifndef __PJMEDIA_AUDIODEV_AUDIOTEST_H__
+#define __PJMEDIA_AUDIODEV_AUDIOTEST_H__
/**
* @file audiotest.h
@@ -91,7 +91,7 @@
/**
* Perform audio device testing.
*/
-PJ_DECL(pj_status_t) pjmedia_aud_test(const pjmedia_aud_dev_param *param,
+PJ_DECL(pj_status_t) pjmedia_aud_test(const pjmedia_aud_param *param,
pjmedia_aud_test_results *result);
/**
@@ -101,6 +101,6 @@
PJ_END_DECL
-#endif /* __AUDIOTEST_H__ */
+#endif /* __PJMEDIA_AUDIODEV_AUDIOTEST_H__ */
diff --git a/pjmedia/include/pjmedia.h b/pjmedia/include/pjmedia.h
index 55e8977..836a399 100644
--- a/pjmedia/include/pjmedia.h
+++ b/pjmedia/include/pjmedia.h
@@ -52,7 +52,10 @@
#include <pjmedia/sdp_neg.h>
#include <pjmedia/session.h>
#include <pjmedia/silencedet.h>
+/* This sound API is deprecated. Please see:
+http://trac.pjsip.org/repos/wiki/Audio_Dev_API
#include <pjmedia/sound.h>
+*/
#include <pjmedia/sound_port.h>
#include <pjmedia/splitcomb.h>
#include <pjmedia/stereo.h>
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h
index 870b228..915b732 100644
--- a/pjmedia/include/pjmedia/config.h
+++ b/pjmedia/include/pjmedia/config.h
@@ -64,99 +64,68 @@
* Types of sound stream backends.
*/
-/** Constant for NULL sound backend. */
-#define PJMEDIA_SOUND_NULL_SOUND 0
-
-/** Constant for PortAudio sound backend. */
-#define PJMEDIA_SOUND_PORTAUDIO_SOUND 1
-
-/** Constant for Win32 DirectSound sound backend. */
-#define PJMEDIA_SOUND_WIN32_DIRECT_SOUND 2
-
-/** Constant for Win32 MME sound backend. */
-#define PJMEDIA_SOUND_WIN32_MME_SOUND 3
-
-/** Constant for Symbian Multimedia Audio Stream backend. */
-#define PJMEDIA_SOUND_SYMB_MDA_SOUND 4
-
-/** Constant for Symbian APS backend. */
-#define PJMEDIA_SOUND_SYMB_APS_SOUND 5
-
-/** Constant for Symbian VAS backend. */
-#define PJMEDIA_SOUND_SYMB_VAS_SOUND 6
-
-
-/** When this is set, pjmedia will not provide any sound device backend.
- * Application will have to provide its own sound device backend
- * and link the application with it.
- */
-#define PJMEDIA_SOUND_EXTERNAL 255
-
-
/**
- * Unless specified otherwise, sound device uses PortAudio implementation
- * by default.
+ * This macro has been deprecated in releasee 1.1. Please see
+ * http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more information.
*/
-#ifndef PJMEDIA_SOUND_IMPLEMENTATION
-# if defined(PJ_WIN32) && PJ_WIN32!=0
-/*# define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_WIN32_DIRECT_SOUND*/
-/*# define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_WIN32_MME_SOUND*/
-# define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_PORTAUDIO_SOUND
-# else
-# define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_PORTAUDIO_SOUND
-# endif
+#if defined(PJMEDIA_SOUND_IMPLEMENTATION)
+# error PJMEDIA_SOUND_IMPLEMENTATION has been deprecated
#endif
/**
- * Specify if the sound device implementation supports handling encoded
- * frames. Setting this to zero will activate some emulation in the
- * sound port.
+ * This macro has been deprecated in releasee 1.1. Please see
+ * http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more information.
*/
-#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_SYMB_APS_SOUND || \
- PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_SYMB_VAS_SOUND
-# define PJMEDIA_SND_SUPPORT_OPEN2 1
-#else
-# define PJMEDIA_SND_SUPPORT_OPEN2 0
+#if defined(PJMEDIA_PREFER_DIRECT_SOUND)
+# error PJMEDIA_PREFER_DIRECT_SOUND has been deprecated
#endif
/**
- * Specify whether we prefer to use DirectSound on Windows.
- *
- * Default: 0
+ * Setting PJMEDIA_AUDIO_API to this value will completely deprecate the use
+ * of old API, and inclusion of <pjmedia/sound.h> in the code will raise
+ * compilation error.
*/
-#ifndef PJMEDIA_PREFER_DIRECT_SOUND
-# define PJMEDIA_PREFER_DIRECT_SOUND 0
+#define PJMEDIA_AUDIO_API_NEW_ONLY 1
+
+/**
+ * Setting PJMEDIA_AUDIO_API to this value enables application to use the old
+ * sound device API to access audio devices provided by the new audio device
+ * API.
+ */
+#define PJMEDIA_AUDIO_API_HAS_OLD_API 2
+
+/**
+ * Setting PJMEDIA_AUDIO_API to this value enables old sound device
+ * implementation to be accessed via both old and new API's.
+ */
+#define PJMEDIA_AUDIO_API_HAS_OLD_DEVICE 3
+
+/**
+ * Specify how the audio API should handle compatibility with old sound API.
+ * Valid values are: PJMEDIA_AUDIO_API_HAS_OLD_API (default,
+ * PJMEDIA_AUDIO_API_NEW_ONLY, or PJMEDIA_AUDIO_API_HAS_OLD_DEVICE. Please
+ * see http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more info.
+ */
+#ifndef PJMEDIA_AUDIO_API
+# define PJMEDIA_AUDIO_API PJMEDIA_AUDIO_API_NEW_ONLY
#endif
/**
- * Specify sound device latency default, in milisecond.
+ * Specify default sound device latency, in milisecond.
*/
#ifndef PJMEDIA_SND_DEFAULT_REC_LATENCY
# define PJMEDIA_SND_DEFAULT_REC_LATENCY 100
#endif
+/**
+ * Specify default sound device latency, in milisecond.
+ */
#ifndef PJMEDIA_SND_DEFAULT_PLAY_LATENCY
# define PJMEDIA_SND_DEFAULT_PLAY_LATENCY 100
#endif
-/**
- * Specify whether delay buffer is used for sound device.
- * When delay buffer is enabled, the sound device callback
- * will be called one after another evenly.
- * The delay buffer also performs the best delay calculation
- * for the sound device, and will try to limit the delay caused
- * by uneven callback calls to this delay.
- *
- * When this setting is enabled, the PJMEDIA_SOUND_BUFFER_COUNT
- * macro will specify the maximum size of the delay buffer.
- */
-#ifndef PJMEDIA_SOUND_USE_DELAYBUF
-# define PJMEDIA_SOUND_USE_DELAYBUF 0
-#endif
-
-
/*
* Types of WSOLA backend algorithm.
*/
diff --git a/pjmedia/include/pjmedia/endpoint.h b/pjmedia/include/pjmedia/endpoint.h
index 0d8dd39..2cc386f 100644
--- a/pjmedia/include/pjmedia/endpoint.h
+++ b/pjmedia/include/pjmedia/endpoint.h
@@ -37,7 +37,6 @@
* to create a media session (#pjmedia_session_create()).
*/
-#include <pjmedia/sound.h>
#include <pjmedia/codec.h>
#include <pjmedia/sdp.h>
diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h
index 8fe3aac..27ac0dd 100644
--- a/pjmedia/include/pjmedia/sound.h
+++ b/pjmedia/include/pjmedia/sound.h
@@ -21,6 +21,15 @@
#define __PJMEDIA_SOUND_H__
+/* This is legacy sound device code, which has been superseded by the
+ * new pjmedia-audiodev framework. Please see the documentation on how
+ * to use this legacy API.
+ */
+#if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY
+# error "The sound device API is deprecated. Please see doc for details."
+#endif
+
+
/**
* @file sound.h
* @brief Sound player and recorder device framework.
diff --git a/pjmedia/include/pjmedia/sound_port.h b/pjmedia/include/pjmedia/sound_port.h
index 4c943a2..7293a4d 100644
--- a/pjmedia/include/pjmedia/sound_port.h
+++ b/pjmedia/include/pjmedia/sound_port.h
@@ -24,7 +24,7 @@
* @file sound_port.h
* @brief Media port connection abstraction to sound device.
*/
-#include <pjmedia/sound.h>
+#include <pjmedia-audiodev/audiodev.h>
#include <pjmedia/port.h>
PJ_BEGIN_DECL
@@ -162,39 +162,17 @@
/**
- * Create unidirectional or bidirectional sound port. This also allows
- * creating sound port with extended settings, e.g: audio format, see
- * #pjmedia_snd_setting.
+ * Create sound device port according to the specified parameters.
*
* @param pool Pool to allocate sound port structure.
- * @param dir Sound device direction.
- * @param rec_id Device index for recorder/capture stream, or
- * -1 to use the first capable device.
- * @param play_id Device index for playback stream, or -1 to use
- * the first capable device.
- * @param clock_rate Sound device's clock rate to set.
- * @param channel_count Set number of channels, 1 for mono, or 2 for
- * stereo. The channel count determines the format
- * of the frame.
- * @param samples_per_frame Number of samples per frame.
- * @param bits_per_sample Set the number of bits per sample. The normal
- * value for this parameter is 16 bits per sample.
- * @param setting Sound device extended settings, see
- * #pjmedia_snd_setting.
+ * @param prm Sound device settings.
* @param p_port Pointer to receive the sound device port instance.
*
* @return PJ_SUCCESS on success, or the appropriate error
* code.
*/
PJ_DECL(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
- pjmedia_dir dir,
- int rec_id,
- int play_id,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned bits_per_sample,
- const pjmedia_snd_setting *setting,
+ const pjmedia_aud_param *prm,
pjmedia_snd_port **p_port);
@@ -216,19 +194,23 @@
*
* @return The sound stream instance.
*/
-PJ_DECL(pjmedia_snd_stream*) pjmedia_snd_port_get_snd_stream(
+PJ_DECL(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream(
pjmedia_snd_port *snd_port);
/**
- * Configure the echo cancellation tail length. By default, echo canceller
- * is enabled in the sound device with the default tail length. After the
- * sound port is created, application can query the current echo canceller
- * tail length by calling #pjmedia_snd_port_get_ec_tail.
+ * Change the echo cancellation settings. The echo cancellation settings
+ * should have been specified when this sound port was created, by setting
+ * the appropriate fields in the pjmedia_aud_param, because not all sound
+ * device implementation supports changing the EC setting once the device
+ * has been opened.
*
- * Note that you should only change the EC settings when the sound port
- * is not connected to any downstream ports, otherwise race condition may
- * occur.
+ * The behavior of this function depends on whether device or software AEC
+ * is being used. If the device supports AEC, this function will forward
+ * the change request to the device and it will be up to the device whether
+ * to support the request. If software AEC is being used (the software EC
+ * will be used if the device does not support AEC), this function will
+ * change the software EC settings.
*
* @param snd_port The sound device port.
* @param pool Pool to re-create the echo canceller if necessary.
@@ -236,6 +218,7 @@
* miliseconds. If zero is specified, the EC would
* be disabled.
* @param options The options to be passed to #pjmedia_echo_create().
+ * This is only used if software EC is being used.
*
* @return PJ_SUCCESS on success.
*/
diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h
index cf5ef47..0227f64 100644
--- a/pjmedia/include/pjmedia/stream.h
+++ b/pjmedia/include/pjmedia/stream.h
@@ -26,7 +26,6 @@
* @brief Media Stream.
*/
-#include <pjmedia/sound.h>
#include <pjmedia/codec.h>
#include <pjmedia/endpoint.h>
#include <pjmedia/port.h>
diff --git a/pjmedia/src/pjmedia-audiodev/audiodev.c b/pjmedia/src/pjmedia-audiodev/audiodev.c
index e2f209d..33e333c 100644
--- a/pjmedia/src/pjmedia-audiodev/audiodev.c
+++ b/pjmedia/src/pjmedia-audiodev/audiodev.c
@@ -19,15 +19,41 @@
*/
#include <pjmedia-audiodev/audiodev_imp.h>
#include <pj/errno.h>
+#include <pj/log.h>
+#include <pj/string.h>
+
+#define THIS_FILE "audiodev.c"
+
+/* Capability names */
+static struct cap_info
+{
+ const char *name;
+ const char *info;
+} cap_infos[] =
+{
+ {"ext-fmt", "Extended/non-PCM format"},
+ {"latency-in", "Input latency/buffer size setting"},
+ {"latency-out", "Output latency/buffer size setting"},
+ {"vol-in", "Input volume setting"},
+ {"vol-out", "Output volume setting"},
+ {"meter-in", "Input meter"},
+ {"meter-out", "Output meter"},
+ {"route-in", "Input routing"},
+ {"route-out", "Output routing"},
+ {"aec", "Accoustic echo cancellation"},
+ {"aec-tail", "Tail length setting for AEC"},
+ {"vad", "Voice activity detection"},
+ {"cng", "Comfort noise generation"},
+ {"plg", "Packet loss concealment"}
+};
+
/*
- * The Device ID seen by application and driver is different.
+ * The device index seen by application and driver is different.
*
- * At application level, device ID is a 32bit value. The high 16bit contains
- * the factory ID, and the low 16bit contains the device index in the
- * specified factory. The device ID may also be -1 to denote default device.
- *
- * At driver level, device ID is a 16bit unsigned integer index.
+ * 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)
@@ -40,20 +66,32 @@
pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf);
#define MAX_DRIVERS 16
+#define MAX_DEVS 64
+
+/* typedef for factory creation function */
+typedef pjmedia_aud_dev_factory* (*create_func_ptr)(pj_pool_factory*);
+
+/* driver structure */
+struct driver
+{
+ 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 */
+};
/* The audio subsystem */
static struct aud_subsys
{
- unsigned init_count;
- pj_pool_factory *pf;
- unsigned factory_cnt;
+ unsigned init_count; /* How many times init() is called */
+ pj_pool_factory *pf; /* The pool factory. */
- struct factory
- {
- pjmedia_aud_dev_factory* (*create)(pj_pool_factory*);
- pjmedia_aud_dev_factory *f;
+ unsigned drv_cnt; /* Number of drivers. */
+ struct driver drv[MAX_DRIVERS]; /* Array of drivers. */
- } factories[MAX_DRIVERS];
+ unsigned dev_cnt; /* Total number of devices. */
+ pj_uint32_t dev_list[MAX_DEVS];/* Array of device IDs. */
} aud_subsys;
@@ -73,29 +111,67 @@
}
aud_subsys.pf = pf;
- aud_subsys.factory_cnt = 0;
+ aud_subsys.drv_cnt = 0;
+ aud_subsys.dev_cnt = 0;
- aud_subsys.factories[aud_subsys.factory_cnt++].create = &pjmedia_pa_factory;
- aud_subsys.factories[aud_subsys.factory_cnt++].create = &pjmedia_wmme_factory;
+ /* Register creation functions */
+ aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
+ aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
- for (i=0; i<aud_subsys.factory_cnt; ++i) {
+ /* Initialize each factory and build the device ID list */
+ for (i=0; i<aud_subsys.drv_cnt; ++i) {
pjmedia_aud_dev_factory *f;
+ pjmedia_aud_dev_info info;
+ unsigned j, dev_cnt;
- f = (*aud_subsys.factories[i].create)(pf);
+ /* Create the factory */
+ f = (*aud_subsys.drv[i].create)(pf);
if (!f)
continue;
+ /* Call factory->init() */
status = f->op->init(f);
if (status != PJ_SUCCESS) {
f->op->destroy(f);
continue;
}
- aud_subsys.factories[i].f = f;
- aud_subsys.factories[i].f->internal.id = i;
+ /* Build device list */
+ dev_cnt = f->op->get_dev_count(f);
+ if (dev_cnt == 0) {
+ f->op->destroy(f);
+ continue;
+ }
+
+ /* Get one device info */
+ status = f->op->get_dev_info(f, 0, &info);
+ if (status != PJ_SUCCESS) {
+ f->op->destroy(f);
+ continue;
+ }
+
+ /* Register the factory */
+ aud_subsys.drv[i].f = f;
+ aud_subsys.drv[i].f->internal.id = i;
+ aud_subsys.drv[i].start_idx = aud_subsys.dev_cnt;
+ pj_ansi_strncpy(aud_subsys.drv[i].name, info.driver,
+ sizeof(aud_subsys.drv[i].name));
+ aud_subsys.drv[i].name[sizeof(aud_subsys.drv[i].name)-1] = '\0';
+
+ /* Register devices */
+ if (aud_subsys.dev_cnt + dev_cnt > MAX_DEVS) {
+ PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
+ " there are too many sound devices",
+ aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));
+ dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;
+ }
+ for (j=0; j<dev_cnt; ++j) {
+ aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(i, j);
+ }
+
}
- return aud_subsys.factory_cnt ? PJ_SUCCESS : status;
+ return aud_subsys.drv_cnt ? PJ_SUCCESS : status;
}
/* API: get the pool factory registered to the audio subsystem. */
@@ -117,167 +193,239 @@
}
--aud_subsys.init_count;
- for (i=0; i<aud_subsys.factory_cnt; ++i) {
- pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f;
+ for (i=0; i<aud_subsys.drv_cnt; ++i) {
+ pjmedia_aud_dev_factory *f = aud_subsys.drv[i].f;
if (!f)
continue;
f->op->destroy(f);
- aud_subsys.factories[i].f = NULL;
+ aud_subsys.drv[i].f = NULL;
}
return PJ_SUCCESS;
}
+/* API: get capability name/info */
+PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
+ const char **p_desc)
+{
+ char *desc;
+ unsigned i;
+
+ if (p_desc==NULL) p_desc = &desc;
+
+ for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
+ if ((1 << i)==cap)
+ break;
+ }
+
+ if (i==32) {
+ *p_desc = "??";
+ return "??";
+ }
+
+ *p_desc = cap_infos[i].info;
+ return cap_infos[i].name;
+}
+
/* API: Get the number of sound devices installed in the system. */
PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
{
- unsigned i, count = 0;
-
- for (i=0; i<aud_subsys.factory_cnt; ++i) {
- pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f;
-
- if (!f)
- continue;
-
- count += f->op->get_dev_count(f);
- }
-
- return count;
+ return aud_subsys.dev_cnt;
}
-/* API: Enumerate device ID's. */
-PJ_DEF(unsigned) pjmedia_aud_dev_enum(unsigned max_count,
- pjmedia_aud_dev_id ids[])
+/* 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)
{
- unsigned i, count = 0;
+ int f_id, index;
- for (i=0; i<aud_subsys.factory_cnt && count < max_count; ++i) {
- pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f;
- unsigned j, fcount;
+ if (id == PJMEDIA_AUD_DEV_DEFAULT)
+ id = DEFAULT_DEV_ID;
- if (!f)
- continue;
+ PJ_ASSERT_RETURN(id>=0 && id<(int)aud_subsys.dev_cnt,
+ PJMEDIA_EAUD_INVDEV);
- fcount = f->op->get_dev_count(f);
- for (j=0; j<fcount && count<max_count; ++j) {
- ids[count++] = MAKE_DEV_ID(i, j);
- }
- }
+ f_id = GET_FID(aud_subsys.dev_list[id]);
+ index = GET_INDEX(aud_subsys.dev_list[id]);
- return count;
+ 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;
+
}
+/* Internal: convert local index to global device index */
+static pj_status_t make_global_index(pjmedia_aud_dev_factory *f,
+ pjmedia_aud_dev_index *id)
+{
+ unsigned f_id = f->internal.id;
+
+ if (*id == PJMEDIA_AUD_DEV_DEFAULT)
+ return PJ_SUCCESS;
+
+ /* Check that factory still exists */
+ PJ_ASSERT_RETURN(f, PJ_EBUG);
+
+ /* Check that device index is valid */
+ PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[f_id].dev_cnt, PJ_EBUG);
+
+ *id += aud_subsys.drv[f_id].start_idx;
+ return PJ_SUCCESS;
+}
/* API: Get device information. */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id,
+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;
- int f_id, index;
+ unsigned index;
+ pj_status_t status;
- if (id == PJMEDIA_AUD_DEV_DEFAULT_ID)
- id = DEFAULT_DEV_ID;
+ PJ_ASSERT_RETURN(info, PJ_EINVAL);
- f_id = GET_FID(id);
- index = GET_INDEX(id);
-
- if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt)
- return PJMEDIA_EAUD_INVDEV;
-
- f = aud_subsys.factories[f_id].f;
- if (f == NULL)
- return PJMEDIA_EAUD_INVDEV;
+ 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 i, j;
+
+ PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
+
+ for (i=0; i<aud_subsys.drv_cnt; ++i) {
+ if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[i].name)) {
+ f = aud_subsys.drv[i].f;
+ break;
+ }
+ }
+
+ if (!f)
+ return PJ_ENOTFOUND;
+
+ for (j=0; j<aud_subsys.drv[i].dev_cnt; ++j) {
+ pjmedia_aud_dev_info info;
+ pj_status_t status;
+
+ status = f->op->get_dev_info(f, j, &info);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ if (!pj_ansi_stricmp(dev_name, info.name))
+ break;
+ }
+
+ if (j==aud_subsys.drv[i].dev_cnt)
+ return PJ_ENOTFOUND;
+
+ *id = j;
+ make_global_index(f, 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_id id,
- pjmedia_aud_dev_param *param)
+PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
+ pjmedia_aud_param *param)
{
pjmedia_aud_dev_factory *f;
- int f_id, index;
+ unsigned index;
pj_status_t status;
- if (id == PJMEDIA_AUD_DEV_DEFAULT_ID)
- id = DEFAULT_DEV_ID;
+ PJ_ASSERT_RETURN(param, PJ_EINVAL);
- f_id = GET_FID(id);
- index = GET_INDEX(id);
-
- if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt)
- return PJMEDIA_EAUD_INVDEV;
-
- f = aud_subsys.factories[f_id].f;
- if (f == NULL)
- return PJMEDIA_EAUD_INVDEV;
+ 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 */
- if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
- param->rec_id = MAKE_DEV_ID(f_id, param->rec_id);
- if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
- param->play_id = MAKE_DEV_ID(f_id, param->play_id);
+ make_global_index(f, ¶m->rec_id);
+ make_global_index(f, ¶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_dev_param *p,
+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 *f;
- pjmedia_aud_dev_param param;
- int f_id;
+ 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);
+
/* Must make copy of param because we're changing device ID */
- pj_memcpy(¶m, p, sizeof(param));
+ pj_memcpy(¶m, prm, sizeof(param));
- /* Set default device */
- if (param.rec_id == PJMEDIA_AUD_DEV_DEFAULT_ID)
- param.rec_id = DEFAULT_DEV_ID;
- if (param.play_id == PJMEDIA_AUD_DEV_DEFAULT_ID)
- param.play_id = DEFAULT_DEV_ID;
+ /* Normalize rec_id */
+ if (param.dir & PJMEDIA_DIR_CAPTURE) {
+ unsigned index;
+
+ 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;
+
+ status = lookup_dev(param.play_id, &play_f, &index);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ param.play_id = index;
+ f = play_f;
+
+ /* For now, rec_id and play_id must belong to the same factory */
+ PJ_ASSERT_RETURN(rec_f == play_f, PJ_EINVAL);
+ }
+
- if (param.dir & PJMEDIA_DIR_CAPTURE)
- f_id = GET_FID(param.rec_id);
- else
- f_id = GET_FID(param.play_id);
-
- if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt)
- return PJMEDIA_EAUD_INVDEV;
-
- /* Normalize device id's */
- param.rec_id = GET_INDEX(param.rec_id);
- param.play_id = GET_INDEX(param.play_id);
-
- f = aud_subsys.factories[f_id].f;
- if (f == NULL)
- return 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;
- (*p_aud_strm)->factory = f;
+ /* Assign factory id to the stream */
+ (*p_aud_strm)->factory_id = f->internal.id;
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_dev_param *param)
+ pjmedia_aud_param *param)
{
pj_status_t status;
@@ -286,10 +434,8 @@
return status;
/* Normalize device id's */
- if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
- param->rec_id = MAKE_DEV_ID(strm->factory->internal.id, param->rec_id);
- if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
- param->play_id = MAKE_DEV_ID(strm->factory->internal.id, param->play_id);
+ make_global_index(aud_subsys.drv[strm->factory_id].f, ¶m->rec_id);
+ make_global_index(aud_subsys.drv[strm->factory_id].f, ¶m->play_id);
return PJ_SUCCESS;
}
diff --git a/pjmedia/src/pjmedia-audiodev/audiotest.c b/pjmedia/src/pjmedia-audiodev/audiotest.c
index 563e1e8..120f710 100644
--- a/pjmedia/src/pjmedia-audiodev/audiotest.c
+++ b/pjmedia/src/pjmedia-audiodev/audiotest.c
@@ -51,7 +51,7 @@
struct test_data
{
pj_pool_t *pool;
- const pjmedia_aud_dev_param *param;
+ const pjmedia_aud_param *param;
pjmedia_aud_test_results *result;
pj_bool_t running;
pj_bool_t has_error;
@@ -181,7 +181,7 @@
}
-PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_dev_param *param,
+PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_param *param,
pjmedia_aud_test_results *result)
{
pj_status_t status = PJ_SUCCESS;
diff --git a/pjmedia/src/pjmedia-audiodev/pa_dev.c b/pjmedia/src/pjmedia-audiodev/pa_dev.c
index 0a0e7a2..4750877 100644
--- a/pjmedia/src/pjmedia-audiodev/pa_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/pa_dev.c
@@ -105,9 +105,9 @@
pjmedia_aud_dev_info *info);
static pj_status_t pa_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t pa_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
@@ -115,7 +115,7 @@
/* Stream prototypes */
static pj_status_t strm_get_param(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t strm_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value);
@@ -514,7 +514,7 @@
/* API: fill in with default parameter. */
static pj_status_t pa_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param)
+ pjmedia_aud_param *param)
{
pjmedia_aud_dev_info adi;
pj_status_t status;
@@ -533,11 +533,11 @@
} else if (adi.input_count) {
param->dir = PJMEDIA_DIR_CAPTURE;
param->rec_id = index;
- param->play_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+ param->play_id = PJMEDIA_AUD_DEV_DEFAULT;
} else if (adi.output_count) {
param->dir = PJMEDIA_DIR_PLAYBACK;
param->play_id = index;
- param->rec_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+ param->rec_id = PJMEDIA_AUD_DEV_DEFAULT;
} else {
return PJMEDIA_EAUD_INVDEV;
}
@@ -669,13 +669,13 @@
/* Internal: create capture/recorder stream */
static pj_status_t create_rec_stream( struct pa_aud_factory *pa,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
void *user_data,
pjmedia_aud_stream **p_snd_strm)
{
pj_pool_t *pool;
- pjmedia_aud_dev_id rec_id;
+ pjmedia_aud_dev_index rec_id;
struct pa_aud_stream *stream;
PaStreamParameters inputParam;
int sampleFormat;
@@ -774,13 +774,13 @@
/* Internal: create playback stream */
static pj_status_t create_play_stream(struct pa_aud_factory *pa,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_snd_strm)
{
pj_pool_t *pool;
- pjmedia_aud_dev_id play_id;
+ pjmedia_aud_dev_index play_id;
struct pa_aud_stream *stream;
PaStreamParameters outputParam;
int sampleFormat;
@@ -881,14 +881,14 @@
/* Internal: Create both player and recorder stream */
static pj_status_t create_bidir_stream(struct pa_aud_factory *pa,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_snd_strm)
{
pj_pool_t *pool;
- pjmedia_aud_dev_id rec_id, play_id;
+ pjmedia_aud_dev_index rec_id, play_id;
struct pa_aud_stream *stream;
PaStream *paStream = NULL;
PaStreamParameters inputParam;
@@ -1060,7 +1060,7 @@
/* API: create stream */
static pj_status_t pa_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
@@ -1091,7 +1091,7 @@
/* API: Get stream parameters */
static pj_status_t strm_get_param(pjmedia_aud_stream *s,
- pjmedia_aud_dev_param *pi)
+ pjmedia_aud_param *pi)
{
struct pa_aud_stream *strm = (struct pa_aud_stream*)s;
const PaStreamInfo *paPlaySI = NULL, *paRecSI = NULL;
diff --git a/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp b/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp
index 4c38cc4..d931275 100644
--- a/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp
+++ b/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp
@@ -71,7 +71,7 @@
pj_pool_t *pool; /**< Memory pool. */
// Common settings.
- pjmedia_aud_dev_param param; /**< Stream param. */
+ pjmedia_aud_param param; /**< Stream param. */
pjmedia_aud_rec_cb rec_cb; /**< Record callback. */
pjmedia_aud_play_cb play_cb; /**< Playback callback. */
void *user_data; /**< Application data. */
@@ -100,16 +100,16 @@
pjmedia_aud_dev_info *info);
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_aud_strm);
static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value);
@@ -1175,7 +1175,7 @@
/* API: create default device parameter */
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param)
+ pjmedia_aud_param *param)
{
struct aps_factory *af = (struct aps_factory*)f;
@@ -1199,7 +1199,7 @@
/* API: create stream */
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
@@ -1332,7 +1332,7 @@
/* API: Get stream info. */
static pj_status_t stream_get_param(pjmedia_aud_stream *s,
- pjmedia_aud_dev_param *pi)
+ pjmedia_aud_param *pi)
{
struct aps_stream *strm = (struct aps_stream*)s;
diff --git a/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp b/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp
index e97807d..02fba93 100644
--- a/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp
+++ b/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp
@@ -72,7 +72,7 @@
pj_pool_t *pool; /**< Memory pool. */
// Common settings.
- pjmedia_aud_dev_param param; /**< Stream param. */
+ pjmedia_aud_param param; /**< Stream param. */
// Audio engine
CPjAudioInputEngine *in_engine; /**< Record engine. */
@@ -89,16 +89,16 @@
pjmedia_aud_dev_info *info);
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_aud_strm);
static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value);
@@ -844,7 +844,7 @@
/* API: create default device parameter */
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param)
+ pjmedia_aud_param *param)
{
struct mda_factory *af = (struct mda_factory*)f;
@@ -866,7 +866,7 @@
/* API: create stream */
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
@@ -921,7 +921,7 @@
/* API: Get stream info. */
static pj_status_t stream_get_param(pjmedia_aud_stream *s,
- pjmedia_aud_dev_param *pi)
+ pjmedia_aud_param *pi)
{
struct mda_stream *strm = (struct mda_stream*)s;
diff --git a/pjmedia/src/pjmedia-audiodev/wmme_dev.c b/pjmedia/src/pjmedia-audiodev/wmme_dev.c
index 5a80101..1458d30 100644
--- a/pjmedia/src/pjmedia-audiodev/wmme_dev.c
+++ b/pjmedia/src/pjmedia-audiodev/wmme_dev.c
@@ -120,16 +120,16 @@
pjmedia_aud_dev_info *info);
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
pjmedia_aud_stream **p_aud_strm);
static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
- pjmedia_aud_dev_param *param);
+ pjmedia_aud_param *param);
static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
pjmedia_aud_dev_cap cap,
void *value);
@@ -398,7 +398,7 @@
/* API: create default device parameter */
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
unsigned index,
- pjmedia_aud_dev_param *param)
+ pjmedia_aud_param *param)
{
struct wmme_factory *wf = (struct wmme_factory*)f;
struct wmme_dev_info *di = &wf->dev_info[index];
@@ -413,11 +413,11 @@
} else if (di->info.input_count) {
param->dir = PJMEDIA_DIR_CAPTURE;
param->rec_id = index;
- param->play_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+ param->play_id = PJMEDIA_AUD_DEV_DEFAULT;
} else if (di->info.output_count) {
param->dir = PJMEDIA_DIR_PLAYBACK;
param->play_id = index;
- param->rec_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+ param->rec_id = PJMEDIA_AUD_DEV_DEFAULT;
} else {
return PJMEDIA_EAUD_INVDEV;
}
@@ -815,7 +815,7 @@
/* API: create stream */
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
- const pjmedia_aud_dev_param *param,
+ const pjmedia_aud_param *param,
pjmedia_aud_rec_cb rec_cb,
pjmedia_aud_play_cb play_cb,
void *user_data,
@@ -929,7 +929,7 @@
/* API: Get stream info. */
static pj_status_t stream_get_param(pjmedia_aud_stream *s,
- pjmedia_aud_dev_param *pi)
+ pjmedia_aud_param *pi)
{
struct wmme_stream *strm = (struct wmme_stream*)s;
diff --git a/pjmedia/src/pjmedia/conf_switch.c b/pjmedia/src/pjmedia/conf_switch.c
index 97cebbe..ca8f3cd 100644
--- a/pjmedia/src/pjmedia/conf_switch.c
+++ b/pjmedia/src/pjmedia/conf_switch.c
@@ -113,7 +113,6 @@
unsigned max_ports; /**< Maximum ports. */
unsigned port_cnt; /**< Current number of ports. */
unsigned connect_cnt; /**< Total number of connections */
- pjmedia_snd_port *snd_dev_port; /**< Sound device port. */
pjmedia_port *master_port; /**< Port zero's port. */
char master_name_buf[80]; /**< Port0 name buffer. */
pj_mutex_t *mutex; /**< Conference mutex. */
@@ -187,67 +186,15 @@
pj_str_t name = { "Master/sound", 12 };
pj_status_t status;
-
status = create_conf_port(pool, conf, conf->master_port, &name, &conf_port);
if (status != PJ_SUCCESS)
return status;
-
- /* Create sound device port: */
-
- if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0) {
- pjmedia_snd_stream *strm;
- pjmedia_snd_stream_info si;
- pjmedia_port_info *master_port_info = (pjmedia_port_info*)
- &conf->master_port->info;
-
- /*
- * If capture is disabled then create player only port.
- * Otherwise create bidirectional sound device port.
- */
- if (conf->options & PJMEDIA_CONF_NO_MIC) {
- status = pjmedia_snd_port_create_player(
- pool, -1,
- master_port_info->clock_rate,
- master_port_info->channel_count,
- master_port_info->samples_per_frame,
- master_port_info->bits_per_sample,
- 0, /* options */
- &conf->snd_dev_port);
-
- } else {
- status = pjmedia_snd_port_create(
- pool, -1, -1,
- master_port_info->clock_rate,
- master_port_info->channel_count,
- master_port_info->samples_per_frame,
- master_port_info->bits_per_sample,
- 0, /* Options */
- &conf->snd_dev_port);
- }
-
- if (status != PJ_SUCCESS)
- return status;
-
- strm = pjmedia_snd_port_get_snd_stream(conf->snd_dev_port);
- status = pjmedia_snd_stream_get_info(strm, &si);
- if (status == PJ_SUCCESS) {
- const pjmedia_snd_dev_info *snd_dev_info;
- if (conf->options & PJMEDIA_CONF_NO_MIC)
- snd_dev_info = pjmedia_snd_get_dev_info(si.play_id);
- else
- snd_dev_info = pjmedia_snd_get_dev_info(si.rec_id);
- pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info->name);
- }
- }
-
-
/* Add the port to the bridge */
conf_port->slot = 0;
conf->ports[0] = conf_port;
conf->port_cnt++;
-
PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0"));
return PJ_SUCCESS;
}
@@ -311,18 +258,6 @@
if (status != PJ_SUCCESS)
return status;
- /* If sound device was created, connect sound device to the
- * master port.
- */
- if (conf->snd_dev_port) {
- status = pjmedia_snd_port_connect( conf->snd_dev_port,
- conf->master_port );
- if (status != PJ_SUCCESS) {
- pjmedia_conf_destroy(conf);
- return status;
- }
- }
-
/* Done */
*p_conf = conf;
@@ -359,12 +294,6 @@
{
PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL);
- /* Destroy sound device port. */
- if (conf->snd_dev_port) {
- pjmedia_snd_port_destroy(conf->snd_dev_port);
- conf->snd_dev_port = NULL;
- }
-
/* Destroy mutex */
pj_mutex_destroy(conf->mutex);
diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c
index 54c4975..a89aff3 100644
--- a/pjmedia/src/pjmedia/conference.c
+++ b/pjmedia/src/pjmedia/conference.c
@@ -465,8 +465,8 @@
/* Create sound device port: */
if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0) {
- pjmedia_snd_stream *strm;
- pjmedia_snd_stream_info si;
+ pjmedia_aud_stream *strm;
+ pjmedia_aud_param param;
/*
* If capture is disabled then create player only port.
@@ -494,14 +494,14 @@
return status;
strm = pjmedia_snd_port_get_snd_stream(conf->snd_dev_port);
- status = pjmedia_snd_stream_get_info(strm, &si);
+ status = pjmedia_aud_stream_get_param(strm, ¶m);
if (status == PJ_SUCCESS) {
- const pjmedia_snd_dev_info *snd_dev_info;
+ pjmedia_aud_dev_info snd_dev_info;
if (conf->options & PJMEDIA_CONF_NO_MIC)
- snd_dev_info = pjmedia_snd_get_dev_info(si.play_id);
+ pjmedia_aud_dev_get_info(param.play_id, &snd_dev_info);
else
- snd_dev_info = pjmedia_snd_get_dev_info(si.rec_id);
- pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info->name);
+ pjmedia_aud_dev_get_info(param.rec_id, &snd_dev_info);
+ pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info.name);
}
}
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
index fb66a81..a3e988d 100644
--- a/pjmedia/src/pjmedia/endpoint.c
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -20,6 +20,7 @@
#include <pjmedia/endpoint.h>
#include <pjmedia/errno.h>
#include <pjmedia/sdp.h>
+#include <pjmedia-audiodev/audiodev.h>
#include <pj/assert.h>
#include <pj/ioqueue.h>
#include <pj/log.h>
@@ -121,7 +122,7 @@
endpt->thread_cnt = worker_cnt;
/* Sound */
- status = pjmedia_snd_init(pf);
+ status = pjmedia_aud_subsys_init(pf);
if (status != PJ_SUCCESS)
goto on_error;
@@ -171,7 +172,7 @@
if (endpt->ioqueue && endpt->own_ioqueue)
pj_ioqueue_destroy(endpt->ioqueue);
- pjmedia_snd_deinit();
+ pjmedia_aud_subsys_shutdown();
pj_pool_release(pool);
return status;
}
@@ -212,7 +213,7 @@
endpt->pf = NULL;
- pjmedia_snd_deinit();
+ pjmedia_aud_subsys_shutdown();
pj_pool_release (endpt->pool);
return PJ_SUCCESS;
diff --git a/pjmedia/src/pjmedia/sound_port.c b/pjmedia/src/pjmedia/sound_port.c
index 5c89699..3a09e9f 100644
--- a/pjmedia/src/pjmedia/sound_port.c
+++ b/pjmedia/src/pjmedia/sound_port.c
@@ -22,13 +22,11 @@
#include <pjmedia/delaybuf.h>
#include <pjmedia/echo.h>
#include <pjmedia/errno.h>
-#include <pjmedia/plc.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/rand.h>
#include <pj/string.h> /* pj_memset() */
-//#define SIMULATE_LOST_PCT 20
#define AEC_TAIL 128 /* default AEC length in ms */
#define AEC_SUSPEND_LIMIT 5 /* seconds of no activity */
@@ -40,107 +38,51 @@
{
int rec_id;
int play_id;
- pjmedia_snd_stream *snd_stream;
+ pj_uint32_t aud_caps;
+ pjmedia_aud_param aud_param;
+ pjmedia_aud_stream *aud_stream;
pjmedia_dir dir;
pjmedia_port *port;
- pjmedia_echo_state *ec_state;
- unsigned aec_tail_len;
-
- pj_bool_t ec_suspended;
- unsigned ec_suspend_count;
- unsigned ec_suspend_limit;
-
- pjmedia_plc *plc;
-
unsigned clock_rate;
unsigned channel_count;
unsigned samples_per_frame;
unsigned bits_per_sample;
- pjmedia_snd_setting setting;
-#if PJMEDIA_SOUND_USE_DELAYBUF
- pjmedia_delay_buf *delay_buf;
-#endif
-
- /* Encoded sound emulation */
-#if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || !PJMEDIA_SND_SUPPORT_OPEN2
- unsigned frm_buf_size;
- pj_uint8_t *put_frm_buf;
- pj_uint8_t *get_frm_buf;
-#endif
+ /* software ec */
+ pjmedia_echo_state *ec_state;
+ unsigned ec_options;
+ unsigned ec_tail_len;
+ pj_bool_t ec_suspended;
+ unsigned ec_suspend_count;
+ unsigned ec_suspend_limit;
};
/*
* The callback called by sound player when it needs more samples to be
* played.
*/
-static pj_status_t play_cb(/* in */ void *user_data,
- /* in */ pj_uint32_t timestamp,
- /* out */ void *output,
- /* out */ unsigned size)
+static pj_status_t play_cb(void *user_data, pjmedia_frame *frame)
{
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
pjmedia_port *port;
- pjmedia_frame frame;
+ unsigned required_size = frame->size;
pj_status_t status;
port = snd_port->port;
if (port == NULL)
goto no_frame;
- frame.buf = output;
- frame.size = size;
- frame.timestamp.u32.hi = 0;
- frame.timestamp.u32.lo = timestamp;
-
-#if PJMEDIA_SOUND_USE_DELAYBUF
- if (snd_port->delay_buf) {
- status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output);
- if (status != PJ_SUCCESS)
- pj_bzero(output, size);
-
- frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
- pjmedia_port_put_frame(port, &frame);
-
-#ifdef TEST_OVERFLOW_UNDERFLOW
- {
- static int count = 1;
- if (++count % 10 == 0) {
- status = pjmedia_delay_buf_get(snd_port->delay_buf,
- (pj_int16_t*)output);
- if (status != PJ_SUCCESS)
- pj_bzero(output, size);
-
- frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
- pjmedia_port_put_frame(port, &frame);
- }
- }
-#endif
-
- }
-#endif
-
- status = pjmedia_port_get_frame(port, &frame);
+ status = pjmedia_port_get_frame(port, frame);
if (status != PJ_SUCCESS)
goto no_frame;
- if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+ if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO)
goto no_frame;
/* Must supply the required samples */
- pj_assert(frame.size == size);
-
-#ifdef SIMULATE_LOST_PCT
- /* Simulate packet lost */
- if (pj_rand() % 100 < SIMULATE_LOST_PCT) {
- PJ_LOG(4,(THIS_FILE, "Frame dropped"));
- goto no_frame;
- }
-#endif
-
- if (snd_port->plc)
- pjmedia_plc_save(snd_port->plc, (pj_int16_t*) output);
+ PJ_UNUSED_ARG(required_size);
+ pj_assert(frame->size == required_size);
if (snd_port->ec_state) {
if (snd_port->ec_suspended) {
@@ -149,7 +91,7 @@
PJ_LOG(4,(THIS_FILE, "EC activated"));
}
snd_port->ec_suspend_count = 0;
- pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output);
+ pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
}
@@ -165,22 +107,10 @@
}
if (snd_port->ec_state) {
/* To maintain correct delay in EC */
- pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output);
+ pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
}
}
- /* Apply PLC */
- if (snd_port->plc) {
-
- pjmedia_plc_generate(snd_port->plc, (pj_int16_t*) output);
-#ifdef SIMULATE_LOST_PCT
- PJ_LOG(4,(THIS_FILE, "Lost frame generated"));
-#endif
- } else {
- pj_bzero(output, size);
- }
-
-
return PJ_SUCCESS;
}
@@ -189,14 +119,10 @@
* The callback called by sound recorder when it has finished capturing a
* frame.
*/
-static pj_status_t rec_cb(/* in */ void *user_data,
- /* in */ pj_uint32_t timestamp,
- /* in */ void *input,
- /* in*/ unsigned size)
+static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame)
{
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
pjmedia_port *port;
- pjmedia_frame frame;
port = snd_port->port;
if (port == NULL)
@@ -204,28 +130,10 @@
/* Cancel echo */
if (snd_port->ec_state && !snd_port->ec_suspended) {
- pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) input, 0);
+ pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0);
}
-#if PJMEDIA_SOUND_USE_DELAYBUF
- if (snd_port->delay_buf) {
- pjmedia_delay_buf_put(snd_port->delay_buf, (pj_int16_t*)input);
- } else {
- frame.buf = (void*)input;
- frame.size = size;
- frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
- frame.timestamp.u32.lo = timestamp;
-
- pjmedia_port_put_frame(port, &frame);
- }
-#else
- frame.buf = (void*)input;
- frame.size = size;
- frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
- frame.timestamp.u32.lo = timestamp;
-
- pjmedia_port_put_frame(port, &frame);
-#endif
+ pjmedia_port_put_frame(port, frame);
return PJ_SUCCESS;
}
@@ -234,118 +142,19 @@
* The callback called by sound player when it needs more samples to be
* played. This version is for non-PCM data.
*/
-static pj_status_t play_cb_ext(/* in */ void *user_data,
- /* in */ pj_uint32_t timestamp,
- /* out */ void *output,
- /* out */ unsigned size)
+static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame)
{
-#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
- /* This is the version to use when the sound device supports
- * open2().
- */
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
- pjmedia_port *port;
- pjmedia_frame *frame = (pjmedia_frame*) output;
- pj_status_t status;
+ pjmedia_port *port = snd_port->port;
- PJ_UNUSED_ARG(size);
- PJ_UNUSED_ARG(timestamp);
-
- port = snd_port->port;
if (port == NULL) {
frame->type = PJMEDIA_FRAME_TYPE_NONE;
return PJ_SUCCESS;
}
- status = pjmedia_port_get_frame(port, frame);
-
- return status;
-#else
- /* This is the emulation version */
- pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
- pjmedia_port *port = snd_port->port;
- pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->get_frm_buf;
- pj_status_t status;
-
- if (port==NULL) {
- goto no_frame;
- }
-
- pj_bzero(fx, sizeof(*fx));
- fx->base.type = PJMEDIA_FRAME_TYPE_NONE;
- fx->base.buf = ((pj_uint8_t*)fx) + sizeof(*fx);
- fx->base.size = snd_port->frm_buf_size - sizeof(*fx);
- fx->base.timestamp.u32.hi = 0;
- fx->base.timestamp.u32.lo = timestamp;
-
- status = pjmedia_port_get_frame(port, &fx->base);
- if (status != PJ_SUCCESS)
- goto no_frame;
-
- if (fx->base.type == PJMEDIA_FRAME_TYPE_AUDIO) {
- pj_assert(fx->base.size == size);
- pj_memcpy(output, fx->base.buf, size);
- } else if (fx->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
- void (*decoder)(pj_int16_t*, const pj_uint8_t*, pj_size_t) = NULL;
- unsigned i, size_decoded;
-
- switch (snd_port->setting.format.id) {
- case PJMEDIA_FORMAT_PCMA:
- decoder = &pjmedia_alaw_decode;
- break;
- case PJMEDIA_FORMAT_PCMU:
- decoder = &pjmedia_ulaw_decode;
- break;
- default:
- PJ_LOG(1,(THIS_FILE, "Unsupported format %d",
- snd_port->setting.format.id));
- goto no_frame;
- }
-
- if (fx->samples_cnt > size>>1) {
- PJ_LOG(4,(THIS_FILE, "Frame too large by %d samples",
- fx->samples_cnt - (size>>1)));
- } else if (fx->samples_cnt < size>>1) {
- PJ_LOG(4,(THIS_FILE, "Not enough frame by %d samples",
- (size>>1) - fx->samples_cnt));
- }
-
- for (i=0, size_decoded=0;
- i<fx->subframe_cnt && size_decoded<size;
- ++i)
- {
- pjmedia_frame_ext_subframe *subfrm;
-
- subfrm = pjmedia_frame_ext_get_subframe(fx, i);
-
- if (!subfrm || subfrm->bitlen==0)
- continue;
-
- if ((subfrm->bitlen>>3) > (int)(size-size_decoded)) {
- subfrm->bitlen = (pj_uint16_t)((size-size_decoded) << 3);
- }
-
- (*decoder)((short*)((pj_uint8_t*)output + size_decoded),
- subfrm->data, subfrm->bitlen>>3);
-
- size_decoded += (subfrm->bitlen>>3) << 1;
- }
-
- if (size_decoded < size) {
- pj_bzero((pj_uint8_t*)output + size_decoded, size-size_decoded);
- }
-
- } else {
- goto no_frame;
- }
+ pjmedia_port_get_frame(port, frame);
return PJ_SUCCESS;
-
-no_frame:
- pj_bzero(output, size);
- return PJ_SUCCESS;
-
-#endif /* PJMEDIA_SND_SUPPORT_OPEN2 */
}
@@ -353,21 +162,10 @@
* The callback called by sound recorder when it has finished capturing a
* frame. This version is for non-PCM data.
*/
-static pj_status_t rec_cb_ext(/* in */ void *user_data,
- /* in */ pj_uint32_t timestamp,
- /* in */ void *input,
- /* in*/ unsigned size)
+static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame)
{
-#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
- /* This is the version to use when the sound device supports
- * open2().
- */
pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
pjmedia_port *port;
- pjmedia_frame *frame = (pjmedia_frame*)input;
-
- PJ_UNUSED_ARG(size);
- PJ_UNUSED_ARG(timestamp);
port = snd_port->port;
if (port == NULL)
@@ -376,42 +174,6 @@
pjmedia_port_put_frame(port, frame);
return PJ_SUCCESS;
-#else
- pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
- pjmedia_port *port = snd_port->port;
- pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->put_frm_buf;
- void (*encoder)(pj_uint8_t*, const pj_int16_t*, pj_size_t) = NULL;
-
- if (port==NULL)
- return PJ_SUCCESS;
-
- pj_bzero(fx, sizeof(*fx));
- fx->base.buf = NULL;
- fx->base.size = snd_port->frm_buf_size - sizeof(*fx);
- fx->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
- fx->base.timestamp.u32.lo = timestamp;
-
- switch (snd_port->setting.format.id) {
- case PJMEDIA_FORMAT_PCMA:
- encoder = &pjmedia_alaw_encode;
- break;
- case PJMEDIA_FORMAT_PCMU:
- encoder = &pjmedia_ulaw_encode;
- break;
- default:
- PJ_LOG(1,(THIS_FILE, "Unsupported format %d",
- snd_port->setting.format.id));
- return PJ_SUCCESS;
- }
-
- (*encoder)((pj_uint8_t*)input, (pj_int16_t*)input, size >> 1);
-
- pjmedia_frame_ext_append_subframe(fx, input, (size >> 1) << 3,
- size >> 1);
- pjmedia_port_put_frame(port, &fx->base);
-
- return PJ_SUCCESS;
-#endif
}
/*
@@ -421,12 +183,13 @@
static pj_status_t start_sound_device( pj_pool_t *pool,
pjmedia_snd_port *snd_port )
{
- pjmedia_snd_rec_cb snd_rec_cb;
- pjmedia_snd_play_cb snd_play_cb;
+ pjmedia_aud_rec_cb snd_rec_cb;
+ pjmedia_aud_play_cb snd_play_cb;
+ pjmedia_aud_param param_copy;
pj_status_t status;
/* Check if sound has been started. */
- if (snd_port->snd_stream != NULL)
+ if (snd_port->aud_stream != NULL)
return PJ_SUCCESS;
PJ_ASSERT_RETURN(snd_port->dir == PJMEDIA_DIR_CAPTURE ||
@@ -434,7 +197,38 @@
snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK,
PJ_EBUG);
- if (snd_port->setting.format.id == PJMEDIA_FORMAT_L16) {
+ /* Get device caps */
+ if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) {
+ pjmedia_aud_dev_info dev_info;
+
+ status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id,
+ &dev_info);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ snd_port->aud_caps = dev_info.caps;
+ } else {
+ snd_port->aud_caps = 0;
+ }
+
+ /* Process EC settings */
+ pj_memcpy(¶m_copy, &snd_port->aud_param, sizeof(param_copy));
+ if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) {
+ /* EC is wanted */
+ if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
+ /* Device supports EC */
+ /* Nothing to do */
+ } else {
+ /* Device doesn't support EC, remove EC settings from
+ * device parameters
+ */
+ param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC |
+ PJMEDIA_AUD_DEV_CAP_EC_TAIL);
+ }
+ }
+
+ /* Use different callback if format is not PCM */
+ if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) {
snd_rec_cb = &rec_cb;
snd_play_cb = &play_cb;
} else {
@@ -442,67 +236,48 @@
snd_play_cb = &play_cb_ext;
}
-#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
- status = pjmedia_snd_open2( snd_port->dir,
- snd_port->rec_id,
- snd_port->play_id,
- snd_port->clock_rate,
- snd_port->channel_count,
- snd_port->samples_per_frame,
- snd_port->bits_per_sample,
- snd_rec_cb,
- snd_play_cb,
- snd_port,
- &snd_port->setting,
- &snd_port->snd_stream);
-#else
- status = pjmedia_snd_open( snd_port->rec_id,
- snd_port->play_id,
- snd_port->clock_rate,
- snd_port->channel_count,
- snd_port->samples_per_frame,
- snd_port->bits_per_sample,
- snd_rec_cb,
- snd_play_cb,
- snd_port,
- &snd_port->snd_stream);
-#endif
+ /* Open the device */
+ status = pjmedia_aud_stream_create(¶m_copy,
+ snd_rec_cb,
+ snd_play_cb,
+ snd_port,
+ &snd_port->aud_stream);
if (status != PJ_SUCCESS)
return status;
-
-#ifdef SIMULATE_LOST_PCT
- snd_port->setting.plc = PJ_TRUE;
-#endif
-
- /* If we have player components, allocate buffer to save the last
- * frame played to the speaker. The last frame is used for packet
- * lost concealment (PLC) algorithm.
- */
- if ((snd_port->dir & PJMEDIA_DIR_PLAYBACK) &&
- (snd_port->setting.plc))
- {
- status = pjmedia_plc_create(pool, snd_port->clock_rate,
- snd_port->samples_per_frame *
- snd_port->channel_count,
- 0, &snd_port->plc);
- if (status != PJ_SUCCESS) {
- PJ_LOG(4,(THIS_FILE, "Unable to create PLC"));
- snd_port->plc = NULL;
- }
- }
-
/* Inactivity limit before EC is suspended. */
snd_port->ec_suspend_limit = AEC_SUSPEND_LIMIT *
(snd_port->clock_rate /
snd_port->samples_per_frame);
+ /* Create software EC if parameter specifies EC but device
+ * doesn't support EC
+ */
+ if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) &&
+ (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0)
+ {
+ if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {
+ snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL;
+ snd_port->aud_param.ec_tail_ms = AEC_TAIL;
+ PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms",
+ snd_port->aud_param.ec_tail_ms));
+ }
+
+ status = pjmedia_snd_port_set_ec(snd_port, pool,
+ snd_port->aud_param.ec_tail_ms, 0);
+ if (status != PJ_SUCCESS) {
+ pjmedia_aud_stream_destroy(snd_port->aud_stream);
+ snd_port->aud_stream = NULL;
+ return status;
+ }
+ }
+
/* Start sound stream. */
- status = pjmedia_snd_stream_start(snd_port->snd_stream);
+ status = pjmedia_aud_stream_start(snd_port->aud_stream);
if (status != PJ_SUCCESS) {
- pjmedia_snd_stream_close(snd_port->snd_stream);
- snd_port->snd_stream = NULL;
+ pjmedia_aud_stream_destroy(snd_port->aud_stream);
+ snd_port->aud_stream = NULL;
return status;
}
@@ -517,10 +292,10 @@
static pj_status_t stop_sound_device( pjmedia_snd_port *snd_port )
{
/* Check if we have sound stream device. */
- if (snd_port->snd_stream) {
- pjmedia_snd_stream_stop(snd_port->snd_stream);
- pjmedia_snd_stream_close(snd_port->snd_stream);
- snd_port->snd_stream = NULL;
+ if (snd_port->aud_stream) {
+ pjmedia_aud_stream_stop(snd_port->aud_stream);
+ pjmedia_aud_stream_destroy(snd_port->aud_stream);
+ snd_port->aud_stream = NULL;
}
/* Destroy AEC */
@@ -546,48 +321,24 @@
unsigned options,
pjmedia_snd_port **p_port)
{
- pjmedia_snd_port *snd_port;
+ pjmedia_aud_param param;
+ pj_status_t status;
PJ_UNUSED_ARG(options);
- PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
+ status = pjmedia_aud_dev_default_param(rec_id, ¶m);
+ if (status != PJ_SUCCESS)
+ return status;
- snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
- PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
+ param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+ param.rec_id = rec_id;
+ param.play_id = play_id;
+ param.clock_rate = clock_rate;
+ param.channel_count = channel_count;
+ param.samples_per_frame = samples_per_frame;
+ param.bits_per_sample = bits_per_sample;
- snd_port->rec_id = rec_id;
- snd_port->play_id = play_id;
- snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
- snd_port->clock_rate = clock_rate;
- snd_port->channel_count = channel_count;
- snd_port->samples_per_frame = samples_per_frame;
- snd_port->bits_per_sample = bits_per_sample;
-
-#if PJMEDIA_SOUND_USE_DELAYBUF
- do {
- pj_status_t status;
- unsigned ptime;
-
- ptime = samples_per_frame * 1000 / (clock_rate * channel_count);
-
- status = pjmedia_delay_buf_create(pool, "snd_buff",
- clock_rate, samples_per_frame,
- channel_count,
- PJMEDIA_SOUND_BUFFER_COUNT * ptime,
- 0, &snd_port->delay_buf);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- } while (0);
-#endif
-
- *p_port = snd_port;
-
-
- /* Start sound device immediately.
- * If there's no port connected, the sound callback will return
- * empty signal.
- */
- return start_sound_device( pool, snd_port );
-
+ return pjmedia_snd_port_create2(pool, ¶m, p_port);
}
/*
@@ -602,29 +353,23 @@
unsigned options,
pjmedia_snd_port **p_port)
{
- pjmedia_snd_port *snd_port;
+ pjmedia_aud_param param;
+ pj_status_t status;
PJ_UNUSED_ARG(options);
- PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
+ status = pjmedia_aud_dev_default_param(dev_id, ¶m);
+ if (status != PJ_SUCCESS)
+ return status;
- snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
- PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
+ param.dir = PJMEDIA_DIR_CAPTURE;
+ param.rec_id = dev_id;
+ param.clock_rate = clock_rate;
+ param.channel_count = channel_count;
+ param.samples_per_frame = samples_per_frame;
+ param.bits_per_sample = bits_per_sample;
- snd_port->rec_id = dev_id;
- snd_port->dir = PJMEDIA_DIR_CAPTURE;
- snd_port->clock_rate = clock_rate;
- snd_port->channel_count = channel_count;
- snd_port->samples_per_frame = samples_per_frame;
- snd_port->bits_per_sample = bits_per_sample;
-
- *p_port = snd_port;
-
- /* Start sound device immediately.
- * If there's no port connected, the sound callback will return
- * empty signal.
- */
- return start_sound_device( pool, snd_port );
+ return pjmedia_snd_port_create2(pool, ¶m, p_port);
}
@@ -640,92 +385,50 @@
unsigned options,
pjmedia_snd_port **p_port)
{
- pjmedia_snd_port *snd_port;
+ pjmedia_aud_param param;
+ pj_status_t status;
PJ_UNUSED_ARG(options);
- PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
+ status = pjmedia_aud_dev_default_param(dev_id, ¶m);
+ if (status != PJ_SUCCESS)
+ return status;
- snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
- PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
+ param.dir = PJMEDIA_DIR_PLAYBACK;
+ param.play_id = dev_id;
+ param.clock_rate = clock_rate;
+ param.channel_count = channel_count;
+ param.samples_per_frame = samples_per_frame;
+ param.bits_per_sample = bits_per_sample;
- snd_port->play_id = dev_id;
- snd_port->dir = PJMEDIA_DIR_PLAYBACK;
- snd_port->clock_rate = clock_rate;
- snd_port->channel_count = channel_count;
- snd_port->samples_per_frame = samples_per_frame;
- snd_port->bits_per_sample = bits_per_sample;
-
- *p_port = snd_port;
-
- /* Start sound device immediately.
- * If there's no port connected, the sound callback will return
- * empty signal.
- */
- return start_sound_device( pool, snd_port );
+ return pjmedia_snd_port_create2(pool, ¶m, p_port);
}
/*
- * Create bidirectional port.
+ * Create sound port.
*/
PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
- pjmedia_dir dir,
- int rec_id,
- int play_id,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned bits_per_sample,
- const pjmedia_snd_setting *setting,
+ const pjmedia_aud_param *prm,
pjmedia_snd_port **p_port)
{
pjmedia_snd_port *snd_port;
- PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
+ PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL);
snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
- snd_port->dir = dir;
- snd_port->rec_id = rec_id;
- snd_port->play_id = play_id;
+ snd_port->dir = prm->dir;
+ snd_port->rec_id = prm->rec_id;
+ snd_port->play_id = prm->play_id;
snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
- snd_port->clock_rate = clock_rate;
- snd_port->channel_count = channel_count;
- snd_port->samples_per_frame = samples_per_frame;
- snd_port->bits_per_sample = bits_per_sample;
- pj_memcpy(&snd_port->setting, setting, sizeof(*setting));
+ snd_port->clock_rate = prm->clock_rate;
+ snd_port->channel_count = prm->channel_count;
+ snd_port->samples_per_frame = prm->samples_per_frame;
+ snd_port->bits_per_sample = prm->bits_per_sample;
+ pj_memcpy(&snd_port->aud_param, prm, sizeof(*prm));
-#if PJMEDIA_SOUND_USE_DELAYBUF
- if (snd_port->setting.format.u32 == PJMEDIA_FORMAT_L16) {
- pj_status_t status;
- unsigned ptime;
-
- ptime = samples_per_frame * 1000 / (clock_rate * channel_count);
-
- status = pjmedia_delay_buf_create(pool, "snd_buff",
- clock_rate, samples_per_frame,
- channel_count,
- PJMEDIA_SOUND_BUFFER_COUNT * ptime,
- 0, &snd_port->delay_buf);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
- }
-#endif
-
-#if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || PJMEDIA_SND_SUPPORT_OPEN2==0
- /* For devices that doesn't support open2(), enable simulation */
- if (snd_port->setting.format.id != PJMEDIA_FORMAT_L16) {
- snd_port->frm_buf_size = sizeof(pjmedia_frame_ext) +
- (samples_per_frame << 1) +
- 16 * sizeof(pjmedia_frame_ext_subframe);
- snd_port->put_frm_buf = (pj_uint8_t*)
- pj_pool_alloc(pool, snd_port->frm_buf_size);
- snd_port->get_frm_buf = (pj_uint8_t*)
- pj_pool_alloc(pool, snd_port->frm_buf_size);
- }
-#endif
-
*p_port = snd_port;
@@ -752,23 +455,23 @@
/*
* Retrieve the sound stream associated by this sound device port.
*/
-PJ_DEF(pjmedia_snd_stream*) pjmedia_snd_port_get_snd_stream(
+PJ_DEF(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream(
pjmedia_snd_port *snd_port)
{
PJ_ASSERT_RETURN(snd_port, NULL);
- return snd_port->snd_stream;
+ return snd_port->aud_stream;
}
/*
- * Enable AEC
+ * Change EC settings.
*/
PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port,
pj_pool_t *pool,
unsigned tail_ms,
unsigned options)
{
- pjmedia_snd_stream_info si;
+ pjmedia_aud_param prm;
pj_status_t status;
/* Sound must be opened in full-duplex mode */
@@ -776,43 +479,100 @@
snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK,
PJ_EINVALIDOP);
- /* Sound port must have 16bits per sample */
- PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16,
- PJ_EINVALIDOP);
+ /* Determine whether we use device or software EC */
+ if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
+ /* We use device EC */
+ pj_bool_t ec_enabled;
- /* Destroy AEC */
- if (snd_port->ec_state) {
- pjmedia_echo_destroy(snd_port->ec_state);
- snd_port->ec_state = NULL;
- }
-
- snd_port->aec_tail_len = tail_ms;
-
- if (tail_ms != 0) {
- unsigned delay_ms;
-
- status = pjmedia_snd_stream_get_info(snd_port->snd_stream, &si);
+ /* Query EC status */
+ status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
+ PJMEDIA_AUD_DEV_CAP_EC,
+ &ec_enabled);
if (status != PJ_SUCCESS)
- si.rec_latency = si.play_latency = 0;
+ return status;
- //No need to add input latency in the latency calculation,
- //since actual input latency should be zero.
- //delay_ms = (si.rec_latency + si.play_latency) * 1000 /
- // snd_port->clock_rate;
- delay_ms = si.play_latency * 1000 / snd_port->clock_rate;
- status = pjmedia_echo_create2(pool, snd_port->clock_rate,
- snd_port->channel_count,
- snd_port->samples_per_frame,
- tail_ms, delay_ms,
- options, &snd_port->ec_state);
- if (status != PJ_SUCCESS)
- snd_port->ec_state = NULL;
- else
- snd_port->ec_suspended = PJ_FALSE;
+ if (tail_ms != 0) {
+ /* Change EC setting */
+
+ if (!ec_enabled) {
+ /* Enable EC first */
+ pj_bool_t value = PJ_TRUE;
+ status = pjmedia_aud_stream_set_cap(snd_port->aud_stream,
+ PJMEDIA_AUD_DEV_CAP_EC,
+ &value);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
+
+ if ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {
+ /* Device does not support setting EC tail */
+ return PJMEDIA_EAUD_INVCAP;
+ }
+
+ return pjmedia_aud_stream_set_cap(snd_port->aud_stream,
+ PJMEDIA_AUD_DEV_CAP_EC_TAIL,
+ &tail_ms);
+
+ } else if (ec_enabled) {
+ /* Disable EC */
+ pj_bool_t value = PJ_FALSE;
+ return pjmedia_aud_stream_set_cap(snd_port->aud_stream,
+ PJMEDIA_AUD_DEV_CAP_EC,
+ &value);
+ } else {
+ /* Request to disable EC but EC has been disabled */
+ /* Do nothing */
+ return PJ_SUCCESS;
+ }
+
} else {
- PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the "
- "sound port"));
- status = PJ_SUCCESS;
+ /* We use software EC */
+ /* Sound port must have 16bits per sample */
+ PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16,
+ PJ_EINVALIDOP);
+
+ /* Check if there is change in parameters */
+ if (tail_ms==snd_port->ec_tail_len && options==snd_port->ec_options) {
+ PJ_LOG(5,(THIS_FILE, "pjmedia_snd_port_set_ec() ignored, no "
+ "change in settings"));
+ return PJ_SUCCESS;
+ }
+
+ /* Destroy AEC */
+ if (snd_port->ec_state) {
+ pjmedia_echo_destroy(snd_port->ec_state);
+ snd_port->ec_state = NULL;
+ }
+
+ snd_port->ec_options = options;
+ snd_port->ec_tail_len = tail_ms;
+
+ if (tail_ms != 0) {
+ unsigned delay_ms;
+
+ status = pjmedia_aud_stream_get_param(snd_port->aud_stream, &prm);
+ if (status != PJ_SUCCESS)
+ prm.input_latency_ms = prm.output_latency_ms = 0;
+
+ //No need to add input latency in the latency calculation,
+ //since actual input latency should be zero.
+ //delay_ms = (si.rec_latency + si.play_latency) * 1000 /
+ // snd_port->clock_rate;
+ delay_ms = prm.output_latency_ms;
+ status = pjmedia_echo_create2(pool, snd_port->clock_rate,
+ snd_port->channel_count,
+ snd_port->samples_per_frame,
+ tail_ms, delay_ms,
+ options, &snd_port->ec_state);
+ if (status != PJ_SUCCESS)
+ snd_port->ec_state = NULL;
+ else
+ snd_port->ec_suspended = PJ_FALSE;
+ } else {
+ PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the "
+ "sound port"));
+ status = PJ_SUCCESS;
+ }
}
return status;
@@ -824,12 +584,42 @@
unsigned *p_length)
{
PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL);
- *p_length = snd_port->ec_state ? snd_port->aec_tail_len : 0;
+
+ /* Determine whether we use device or software EC */
+ if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
+ /* We use device EC */
+ pj_bool_t ec_enabled;
+ pj_status_t status;
+
+ /* Query EC status */
+ status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
+ PJMEDIA_AUD_DEV_CAP_EC,
+ &ec_enabled);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ if (!ec_enabled) {
+ *p_length = 0;
+ } else if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) {
+ /* Get device EC tail */
+ status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
+ PJMEDIA_AUD_DEV_CAP_EC_TAIL,
+ p_length);
+ if (status != PJ_SUCCESS)
+ return status;
+ } else {
+ /* Just use default */
+ *p_length = AEC_TAIL;
+ }
+
+ } else {
+ /* We use software EC */
+ *p_length = snd_port->ec_state ? snd_port->ec_tail_len : 0;
+ }
return PJ_SUCCESS;
}
-
/*
* Connect a port.
*/
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c
index 7e0b6b7..77a2e34 100644
--- a/pjmedia/src/pjmedia/transport_ice.c
+++ b/pjmedia/src/pjmedia/transport_ice.c
@@ -21,6 +21,7 @@
#include <pjnath/errno.h>
#include <pj/assert.h>
#include <pj/log.h>
+#include <pj/pool.h>
#include <pj/rand.h>
#define THIS_FILE "transport_ice.c"
diff --git a/pjmedia/src/pjmedia/transport_loop.c b/pjmedia/src/pjmedia/transport_loop.c
index d9742d2..418e04a 100644
--- a/pjmedia/src/pjmedia/transport_loop.c
+++ b/pjmedia/src/pjmedia/transport_loop.c
@@ -22,6 +22,7 @@
#include <pj/errno.h>
#include <pj/ioqueue.h>
#include <pj/log.h>
+#include <pj/pool.h>
#include <pj/rand.h>
#include <pj/string.h>
diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c
index 1170271..2236392 100644
--- a/pjmedia/src/pjmedia/transport_udp.c
+++ b/pjmedia/src/pjmedia/transport_udp.c
@@ -23,6 +23,7 @@
#include <pj/errno.h>
#include <pj/ioqueue.h>
#include <pj/log.h>
+#include <pj/pool.h>
#include <pj/rand.h>
#include <pj/string.h>
diff --git a/pjmedia/src/pjmedia/wmme_sound.c b/pjmedia/src/pjmedia/wmme_sound.c
index 8f94660..e69de29 100644
--- a/pjmedia/src/pjmedia/wmme_sound.c
+++ b/pjmedia/src/pjmedia/wmme_sound.c
@@ -1,1008 +0,0 @@
-#include <pjmedia/sound.h>
-#include <pjmedia/errno.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/string.h>
-
-#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_WIN32_MME_SOUND
-
-#ifdef _MSC_VER
-# pragma warning(push, 3)
-#endif
-
-#include <windows.h>
-#include <mmsystem.h>
-
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
-
-#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
-# pragma comment(lib, "Coredll.lib")
-#elif defined(_MSC_VER)
-# pragma comment(lib, "winmm.lib")
-#endif
-
-
-#define THIS_FILE "wmme_sound.c"
-#define BITS_PER_SAMPLE 16
-#define BYTES_PER_SAMPLE (BITS_PER_SAMPLE/8)
-
-#define MAX_PACKET_BUFFER_COUNT 32
-#define MAX_HARDWARE 16
-
-struct wmme_dev_info
-{
- pjmedia_snd_dev_info info;
- unsigned deviceId;
-};
-
-static unsigned dev_count;
-static struct wmme_dev_info dev_info[MAX_HARDWARE];
-static pj_bool_t snd_initialized = PJ_FALSE;
-
-/* Latency settings */
-static unsigned snd_input_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY;
-static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
-
-
-/* Individual WMME capture/playback stream descriptor */
-struct wmme_stream
-{
- union
- {
- HWAVEIN In;
- HWAVEOUT Out;
- } hWave;
-
- WAVEHDR *WaveHdr;
- HANDLE hEvent;
- DWORD dwBufIdx;
- DWORD dwMaxBufIdx;
- pj_timestamp timestamp;
-};
-
-
-/* Sound stream. */
-struct pjmedia_snd_stream
-{
- pjmedia_dir dir; /**< Sound direction. */
- int play_id; /**< Playback dev id. */
- int rec_id; /**< Recording dev id. */
- pj_pool_t *pool; /**< Memory pool. */
-
- pjmedia_snd_rec_cb rec_cb; /**< Capture callback. */
- pjmedia_snd_play_cb play_cb; /**< Playback callback. */
- void *user_data; /**< Application data. */
-
- struct wmme_stream play_strm; /**< Playback stream. */
- struct wmme_stream rec_strm; /**< Capture stream. */
-
- void *buffer; /**< Temp. frame buffer. */
- unsigned clock_rate; /**< Clock rate. */
- unsigned samples_per_frame; /**< Samples per frame. */
- unsigned bits_per_sample; /**< Bits per sample. */
- unsigned channel_count; /**< Channel count. */
-
- pj_thread_t *thread; /**< Thread handle. */
- HANDLE thread_quit_event; /**< Quit signal to thread */
-};
-
-
-static pj_pool_factory *pool_factory;
-
-static void init_waveformatex (LPWAVEFORMATEX pcmwf,
- unsigned clock_rate,
- unsigned channel_count)
-{
- pj_bzero(pcmwf, sizeof(PCMWAVEFORMAT));
- pcmwf->wFormatTag = WAVE_FORMAT_PCM;
- pcmwf->nChannels = (pj_uint16_t)channel_count;
- pcmwf->nSamplesPerSec = clock_rate;
- pcmwf->nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE);
- pcmwf->nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE;
- pcmwf->wBitsPerSample = BITS_PER_SAMPLE;
-}
-
-
-/*
- * Initialize WMME player device.
- */
-static pj_status_t init_player_stream( pj_pool_t *pool,
- struct wmme_stream *wmme_strm,
- int dev_id,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned buffer_count)
-{
- MMRESULT mr;
- WAVEFORMATEX pcmwf;
- unsigned bytes_per_frame;
- unsigned i;
-
- PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);
-
- /* Check device ID */
- if (dev_id == -1)
- dev_id = 0;
-
- PJ_ASSERT_RETURN(dev_id >= 0 && dev_id < (int)dev_count, PJ_EINVAL);
-
- /*
- * Create a wait event.
- */
- wmme_strm->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (NULL == wmme_strm->hEvent)
- return pj_get_os_error();
-
- /*
- * Set up wave format structure for opening the device.
- */
- init_waveformatex(&pcmwf, clock_rate, channel_count);
- bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-
- /*
- * Open wave device.
- */
- mr = waveOutOpen(&wmme_strm->hWave.Out, dev_info[dev_id].deviceId, &pcmwf,
- (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
-
- /* Pause the wave out device */
- mr = waveOutPause(wmme_strm->hWave.Out);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
-
- /*
- * Create the buffers.
- */
- wmme_strm->WaveHdr = pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count);
- for (i = 0; i < buffer_count; ++i)
- {
- wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame);
- wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame;
- mr = waveOutPrepareHeader(wmme_strm->hWave.Out,
- &(wmme_strm->WaveHdr[i]),
- sizeof(WAVEHDR));
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
- mr = waveOutWrite(wmme_strm->hWave.Out, &(wmme_strm->WaveHdr[i]),
- sizeof(WAVEHDR));
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
- }
-
- wmme_strm->dwBufIdx = 0;
- wmme_strm->dwMaxBufIdx = buffer_count;
- wmme_strm->timestamp.u64 = 0;
-
- /* Done setting up play device. */
- PJ_LOG(5, (THIS_FILE,
- " WaveAPI Sound player \"%s\" initialized (clock_rate=%d, "
- "channel_count=%d, samples_per_frame=%d (%dms))",
- dev_info[dev_id].info.name,
- clock_rate, channel_count, samples_per_frame,
- samples_per_frame * 1000 / clock_rate));
-
- return PJ_SUCCESS;
-}
-
-
-/*
- * Initialize Windows Multimedia recorder device
- */
-static pj_status_t init_capture_stream( pj_pool_t *pool,
- struct wmme_stream *wmme_strm,
- int dev_id,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned buffer_count)
-{
- MMRESULT mr;
- WAVEFORMATEX pcmwf;
- unsigned bytes_per_frame;
- unsigned i;
-
- PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);
-
- /* Check device ID */
- if (dev_id == -1)
- dev_id = 0;
-
- PJ_ASSERT_RETURN(dev_id >= 0 && dev_id < (int)dev_count, PJ_EINVAL);
-
- /*
- * Create a wait event.
- */
- wmme_strm->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (NULL == wmme_strm->hEvent)
- return pj_get_os_error();
-
- /*
- * Set up wave format structure for opening the device.
- */
- init_waveformatex(&pcmwf, clock_rate, channel_count);
- bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-
- /*
- * Open wave device.
- */
- mr = waveInOpen(&wmme_strm->hWave.In, dev_info[dev_id].deviceId, &pcmwf,
- (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
-
- /*
- * Create the buffers.
- */
- wmme_strm->WaveHdr = pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count);
- for (i = 0; i < buffer_count; ++i)
- {
- wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame);
- wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame;
- mr = waveInPrepareHeader(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]),
- sizeof(WAVEHDR));
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
- mr = waveInAddBuffer(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]),
- sizeof(WAVEHDR));
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This is for HRESULT/GetLastError() */
- PJ_RETURN_OS_ERROR(mr);
- }
-
- wmme_strm->dwBufIdx = 0;
- wmme_strm->dwMaxBufIdx = buffer_count;
- wmme_strm->timestamp.u64 = 0;
-
- /* Done setting up play device. */
- PJ_LOG(5,(THIS_FILE,
- " WaveAPI Sound recorder \"%s\" initialized (clock_rate=%d, "
- "channel_count=%d, samples_per_frame=%d (%dms))",
- dev_info[dev_id].info.name,
- clock_rate, channel_count, samples_per_frame,
- samples_per_frame * 1000 / clock_rate));
-
- return PJ_SUCCESS;
-}
-
-
-
-/*
-* WMME capture and playback thread.
-*/
-static int PJ_THREAD_FUNC wmme_dev_thread(void *arg)
-{
- pjmedia_snd_stream *strm = arg;
- HANDLE events[3];
- unsigned eventCount;
- unsigned bytes_per_frame;
- pj_status_t status = PJ_SUCCESS;
-
-
- eventCount = 0;
- events[eventCount++] = strm->thread_quit_event;
- if (strm->dir & PJMEDIA_DIR_PLAYBACK)
- events[eventCount++] = strm->play_strm.hEvent;
- if (strm->dir & PJMEDIA_DIR_CAPTURE)
- events[eventCount++] = strm->rec_strm.hEvent;
-
-
- /* Raise self priority. We don't want the audio to be distorted by
- * system activity.
- */
-#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE != 0
- if (strm->dir & PJMEDIA_DIR_PLAYBACK)
- CeSetThreadPriority(GetCurrentThread(), 153);
- else
- CeSetThreadPriority(GetCurrentThread(), 247);
-#else
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
-#endif
-
- /* Calculate bytes per frame */
- bytes_per_frame = strm->samples_per_frame * BYTES_PER_SAMPLE;
-
- /*
- * Loop while not signalled to quit, wait for event objects to be
- * signalled by WMME capture and play buffer.
- */
- while (status == PJ_SUCCESS)
- {
-
- DWORD rc;
- pjmedia_dir signalled_dir;
-
- rc = WaitForMultipleObjects(eventCount, events, FALSE, INFINITE);
- if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0 + eventCount)
- continue;
-
- if (rc == WAIT_OBJECT_0)
- break;
-
- if (rc == (WAIT_OBJECT_0 + 1))
- {
- if (events[1] == strm->play_strm.hEvent)
- signalled_dir = PJMEDIA_DIR_PLAYBACK;
- else
- signalled_dir = PJMEDIA_DIR_CAPTURE;
- }
- else
- {
- if (events[2] == strm->play_strm.hEvent)
- signalled_dir = PJMEDIA_DIR_PLAYBACK;
- else
- signalled_dir = PJMEDIA_DIR_CAPTURE;
- }
-
-
- if (signalled_dir == PJMEDIA_DIR_PLAYBACK)
- {
- struct wmme_stream *wmme_strm = &strm->play_strm;
- MMRESULT mr = MMSYSERR_NOERROR;
- status = PJ_SUCCESS;
-
- /*
- * Windows Multimedia has requested us to feed some frames to
- * playback buffer.
- */
-
- while (wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwFlags & WHDR_DONE)
- {
- void* buffer = wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData;
-
- PJ_LOG(5,(THIS_FILE, "Finished writing buffer %d",
- wmme_strm->dwBufIdx));
-
- /* Get frame from application. */
- status = (*strm->play_cb)(strm->user_data,
- wmme_strm->timestamp.u32.lo,
- buffer,
- bytes_per_frame);
-
- if (status != PJ_SUCCESS)
- break;
-
- /* Write to the device. */
- mr = waveOutWrite(wmme_strm->hWave.Out,
- &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]),
- sizeof(WAVEHDR));
- if (mr != MMSYSERR_NOERROR)
- {
- status = PJ_STATUS_FROM_OS(mr);
- break;
- }
-
- /* Increment position. */
- if (++wmme_strm->dwBufIdx >= wmme_strm->dwMaxBufIdx)
- wmme_strm->dwBufIdx = 0;
- wmme_strm->timestamp.u64 += strm->samples_per_frame /
- strm->channel_count;
- }
- }
- else
- {
- struct wmme_stream *wmme_strm = &strm->rec_strm;
- MMRESULT mr = MMSYSERR_NOERROR;
- status = PJ_SUCCESS;
-
- /*
- * Windows Multimedia has indicated that it has some frames ready
- * in the capture buffer. Get as much frames as possible to
- * prevent overflows.
- */
-#if 0
- {
- static DWORD tc = 0;
- DWORD now = GetTickCount();
- DWORD i = 0;
- DWORD bits = 0;
-
- if (tc == 0) tc = now;
-
- for (i = 0; i < wmme_strm->dwMaxBufIdx; ++i)
- {
- bits = bits << 4;
- bits |= wmme_strm->WaveHdr[i].dwFlags & WHDR_DONE;
- }
- PJ_LOG(5,(THIS_FILE, "Record Signal> Index: %d, Delta: %4.4d, "
- "Flags: %6.6x\n",
- wmme_strm->dwBufIdx,
- now - tc,
- bits));
- tc = now;
- }
-#endif
-
- while (wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwFlags & WHDR_DONE)
- {
- char* buffer = (char*)
- wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData;
- unsigned cap_len =
- wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwBytesRecorded;
-
- /*
- PJ_LOG(5,(THIS_FILE, "Read %d bytes from buffer %d", cap_len,
- wmme_strm->dwBufIdx));
- */
-
- if (cap_len < bytes_per_frame)
- pj_bzero(buffer + cap_len, bytes_per_frame - cap_len);
-
- /* Copy the audio data out of the wave buffer. */
- pj_memcpy(strm->buffer, buffer, bytes_per_frame);
-
- /* Re-add the buffer to the device. */
- mr = waveInAddBuffer(wmme_strm->hWave.In,
- &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]),
- sizeof(WAVEHDR));
- if (mr != MMSYSERR_NOERROR) {
- status = PJ_STATUS_FROM_OS(mr);
- break;
- }
-
- /* Call callback */
- status = (*strm->rec_cb)(strm->user_data,
- wmme_strm->timestamp.u32.lo,
- strm->buffer,
- bytes_per_frame);
-
- if (status != PJ_SUCCESS)
- break;
-
- /* Increment position. */
- if (++wmme_strm->dwBufIdx >= wmme_strm->dwMaxBufIdx)
- wmme_strm->dwBufIdx = 0;
- wmme_strm->timestamp.u64 += strm->samples_per_frame /
- strm->channel_count;
- }
- }
- }
-
- PJ_LOG(5,(THIS_FILE, "WMME: thread stopping.."));
- return 0;
-}
-
-
-/*
-* Init sound library.
-*/
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
- unsigned c;
- int i;
- int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount;
-
- if (snd_initialized)
- return PJ_SUCCESS;
-
- pj_bzero(&dev_info, sizeof(dev_info));
-
- dev_count = 0;
- pool_factory = factory;
-
- /* Enumerate sound playback devices */
- maximumPossibleDeviceCount = 0;
-
- inputDeviceCount = waveInGetNumDevs();
- if (inputDeviceCount > 0)
- /* assume there is a WAVE_MAPPER */
- maximumPossibleDeviceCount += inputDeviceCount + 1;
-
- outputDeviceCount = waveOutGetNumDevs();
- if (outputDeviceCount > 0)
- /* assume there is a WAVE_MAPPER */
- maximumPossibleDeviceCount += outputDeviceCount + 1;
-
- if (maximumPossibleDeviceCount >= MAX_HARDWARE)
- {
- pj_assert(!"Too many hardware found");
- PJ_LOG(3,(THIS_FILE, "Too many hardware found, "
- "some devices will not be listed"));
- }
-
- if (inputDeviceCount > 0)
- {
- /* -1 is the WAVE_MAPPER */
- for (i = -1; i < inputDeviceCount && dev_count < MAX_HARDWARE; ++i)
- {
- UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i);
- WAVEINCAPS wic;
- MMRESULT mr;
-
- pj_bzero(&wic, sizeof(WAVEINCAPS));
-
- mr = waveInGetDevCaps(uDeviceID, &wic, sizeof(WAVEINCAPS));
-
- if (mr == MMSYSERR_NOMEM)
- return PJ_ENOMEM;
-
- if (mr != MMSYSERR_NOERROR)
- continue;
-
-#ifdef UNICODE
- WideCharToMultiByte(CP_ACP, 0, wic.szPname, wcslen(wic.szPname),
- dev_info[dev_count].info.name, 64, NULL, NULL);
-#else
- strncpy(dev_info[dev_count].info.name, wic.szPname, MAXPNAMELEN);
-#endif
- if (uDeviceID == WAVE_MAPPER)
- strcat(dev_info[dev_count].info.name, " - Input");
-
- dev_info[dev_count].info.input_count = wic.wChannels;
- dev_info[dev_count].info.output_count = 0;
- dev_info[dev_count].info.default_samples_per_sec = 44100;
- dev_info[dev_count].deviceId = uDeviceID;
-
- /* Sometimes a device can return a rediculously large number of
- * channels. This happened with an SBLive card on a Windows ME box.
- * It also happens on Win XP!
- */
- if ((dev_info[dev_count].info.input_count < 1) ||
- (dev_info[dev_count].info.input_count > 256))
- dev_info[dev_count].info.input_count = 2;
-
- ++dev_count;
- }
- }
-
- if( outputDeviceCount > 0 )
- {
- /* -1 is the WAVE_MAPPER */
- for (i = -1; i < outputDeviceCount && dev_count < MAX_HARDWARE; ++i)
- {
- UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i);
- WAVEOUTCAPS woc;
- MMRESULT mr;
-
- pj_bzero(&woc, sizeof(WAVEOUTCAPS));
-
- mr = waveOutGetDevCaps(uDeviceID, &woc, sizeof(WAVEOUTCAPS));
-
- if (mr == MMSYSERR_NOMEM)
- return PJ_ENOMEM;
-
- if (mr != MMSYSERR_NOERROR)
- continue;
-
-#ifdef UNICODE
- WideCharToMultiByte(CP_ACP, 0, woc.szPname, wcslen(woc.szPname),
- dev_info[dev_count].info.name, 64, NULL, NULL);
-#else
- strncpy(dev_info[dev_count].info.name, woc.szPname, MAXPNAMELEN);
-#endif
- if (uDeviceID == WAVE_MAPPER)
- strcat(dev_info[dev_count].info.name, " - Output");
-
- dev_info[dev_count].info.output_count = woc.wChannels;
- dev_info[dev_count].info.input_count = 0;
- dev_info[dev_count].deviceId = uDeviceID;
- /* TODO: Perform a search! */
- dev_info[dev_count].info.default_samples_per_sec = 44100;
-
- /* Sometimes a device can return a rediculously large number of channels.
- * This happened with an SBLive card on a Windows ME box.
- * It also happens on Win XP!
- */
- if ((dev_info[dev_count].info.output_count < 1) ||
- (dev_info[dev_count].info.output_count > 256))
- dev_info[dev_count].info.output_count = 2;
-
- ++dev_count;
- }
- }
-
- PJ_LOG(4, (THIS_FILE, "WMME initialized, found %d devices:", dev_count));
- for (c = 0; c < dev_count; ++c)
- {
- PJ_LOG(4, (THIS_FILE, " dev_id %d: %s (in=%d, out=%d)",
- c,
- dev_info[c].info.name,
- dev_info[c].info.input_count,
- dev_info[c].info.output_count));
- }
- return PJ_SUCCESS;
-}
-
-/*
- * Deinitialize sound library.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
- snd_initialized = PJ_FALSE;
- return PJ_SUCCESS;
-}
-
-/*
- * Get device count.
- */
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
- return dev_count;
-}
-
-/*
- * Get device info.
- */
-PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
-{
- if (index == (unsigned)-1)
- index = 0;
-
- PJ_ASSERT_RETURN(index < dev_count, NULL);
-
- return &dev_info[index].info;
-}
-
-
-/*
- * Open stream.
- */
-static pj_status_t open_stream(pjmedia_dir dir,
- int rec_id,
- int play_id,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned bits_per_sample,
- pjmedia_snd_rec_cb rec_cb,
- pjmedia_snd_play_cb play_cb,
- void *user_data,
- pjmedia_snd_stream **p_snd_strm)
-{
- pj_pool_t *pool;
- pjmedia_snd_stream *strm;
- pj_status_t status;
-
-
- /* Make sure sound subsystem has been initialized with
- * pjmedia_snd_init()
- */
- PJ_ASSERT_RETURN(pool_factory != NULL, PJ_EINVALIDOP);
-
-
- /* Can only support 16bits per sample */
- PJ_ASSERT_RETURN(bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
-
- /* Create and Initialize stream descriptor */
- pool = pj_pool_create(pool_factory, "wmme-dev", 1000, 1000, NULL);
- PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
-
- strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream));
- strm->dir = dir;
- strm->play_id = play_id;
- strm->rec_id = rec_id;
- strm->pool = pool;
- strm->rec_cb = rec_cb;
- strm->play_cb = play_cb;
- strm->user_data = user_data;
- strm->clock_rate = clock_rate;
- strm->samples_per_frame = samples_per_frame;
- strm->bits_per_sample = bits_per_sample;
- strm->channel_count = channel_count;
- strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
- if (!strm->buffer)
- {
- pj_pool_release(pool);
- return PJ_ENOMEM;
- }
-
- /* Create player stream */
- if (dir & PJMEDIA_DIR_PLAYBACK)
- {
- unsigned buf_count;
-
- buf_count = snd_output_latency * clock_rate * channel_count /
- samples_per_frame / 1000;
-
- status = init_player_stream(strm->pool,
- &strm->play_strm,
- play_id,
- clock_rate,
- channel_count,
- samples_per_frame,
- buf_count);
-
- if (status != PJ_SUCCESS)
- {
- pjmedia_snd_stream_close(strm);
- return status;
- }
- }
-
- /* Create capture stream */
- if (dir & PJMEDIA_DIR_CAPTURE)
- {
- unsigned buf_count;
-
- buf_count = snd_input_latency * clock_rate * channel_count /
- samples_per_frame / 1000;
-
- status = init_capture_stream(strm->pool,
- &strm->rec_strm,
- rec_id,
- clock_rate,
- channel_count,
- samples_per_frame,
- buf_count);
-
- if (status != PJ_SUCCESS)
- {
- pjmedia_snd_stream_close(strm);
- return status;
- }
- }
-
- /* Create the stop event */
- strm->thread_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (strm->thread_quit_event == NULL)
- return pj_get_os_error();
-
- /* Create and start the thread */
- status = pj_thread_create(pool, "wmme", &wmme_dev_thread, strm, 0, 0,
- &strm->thread);
- if (status != PJ_SUCCESS)
- {
- pjmedia_snd_stream_close(strm);
- return status;
- }
-
- *p_snd_strm = strm;
-
- return PJ_SUCCESS;
-}
-
-/*
- * Open stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open_rec(int index,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned bits_per_sample,
- pjmedia_snd_rec_cb rec_cb,
- void *user_data,
- pjmedia_snd_stream **p_snd_strm)
-{
- PJ_ASSERT_RETURN(rec_cb && p_snd_strm, PJ_EINVAL);
-
- return open_stream( PJMEDIA_DIR_CAPTURE,
- index,
- -1,
- clock_rate,
- channel_count,
- samples_per_frame,
- bits_per_sample,
- rec_cb,
- NULL,
- user_data,
- p_snd_strm);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_player(int index,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned bits_per_sample,
- pjmedia_snd_play_cb play_cb,
- void *user_data,
- pjmedia_snd_stream **p_snd_strm)
-{
- PJ_ASSERT_RETURN(play_cb && p_snd_strm, PJ_EINVAL);
-
- return open_stream( PJMEDIA_DIR_PLAYBACK,
- -1,
- index,
- clock_rate,
- channel_count,
- samples_per_frame,
- bits_per_sample,
- NULL,
- play_cb,
- user_data,
- p_snd_strm);
-}
-
-/*
- * Open both player and recorder.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open(int rec_id,
- int play_id,
- unsigned clock_rate,
- unsigned channel_count,
- unsigned samples_per_frame,
- unsigned bits_per_sample,
- pjmedia_snd_rec_cb rec_cb,
- pjmedia_snd_play_cb play_cb,
- void *user_data,
- pjmedia_snd_stream **p_snd_strm)
-{
- PJ_ASSERT_RETURN(rec_cb && play_cb && p_snd_strm, PJ_EINVAL);
-
- return open_stream( PJMEDIA_DIR_CAPTURE_PLAYBACK,
- rec_id,
- play_id,
- clock_rate,
- channel_count,
- samples_per_frame,
- bits_per_sample,
- rec_cb,
- play_cb,
- user_data,
- p_snd_strm);
-}
-
-/*
- * Get stream info.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
- pjmedia_snd_stream_info *pi)
-{
- PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-
- pj_bzero(pi, sizeof(*pi));
- pi->dir = strm->dir;
- pi->play_id = strm->play_id;
- pi->rec_id = strm->rec_id;
- pi->clock_rate = strm->clock_rate;
- pi->channel_count = strm->channel_count;
- pi->samples_per_frame = strm->samples_per_frame;
- pi->bits_per_sample = strm->bits_per_sample;
- pi->rec_latency = snd_input_latency * strm->clock_rate *
- strm->channel_count / 1000;
- pi->play_latency = snd_output_latency * strm->clock_rate *
- strm->channel_count / 1000;
-
- return PJ_SUCCESS;
-}
-
-
-/*
-* Start stream.
-*/
-PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
-{
- MMRESULT mr;
-
- PJ_UNUSED_ARG(stream);
-
- if (stream->play_strm.hWave.Out != NULL)
- {
- mr = waveOutRestart(stream->play_strm.hWave.Out);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This macro is supposed to be used for HRESULT, fix. */
- PJ_RETURN_OS_ERROR(mr);
- PJ_LOG(5,(THIS_FILE, "WMME playback stream started"));
- }
-
- if (stream->rec_strm.hWave.In != NULL)
- {
- mr = waveInStart(stream->rec_strm.hWave.In);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This macro is supposed to be used for HRESULT, fix. */
- PJ_RETURN_OS_ERROR(mr);
- PJ_LOG(5,(THIS_FILE, "WMME capture stream started"));
- }
-
- return PJ_SUCCESS;
-}
-
-/*
- * Stop stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
- MMRESULT mr;
-
- PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
- if (stream->play_strm.hWave.Out != NULL)
- {
- mr = waveOutPause(stream->play_strm.hWave.Out);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This macro is supposed to be used for HRESULT, fix. */
- PJ_RETURN_OS_ERROR(mr);
- PJ_LOG(5,(THIS_FILE, "Stopped WMME playback stream"));
- }
-
- if (stream->rec_strm.hWave.In != NULL)
- {
- mr = waveInStop(stream->rec_strm.hWave.In);
- if (mr != MMSYSERR_NOERROR)
- /* TODO: This macro is supposed to be used for HRESULT, fix. */
- PJ_RETURN_OS_ERROR(mr);
- PJ_LOG(5,(THIS_FILE, "Stopped WMME capture stream"));
- }
-
- return PJ_SUCCESS;
-}
-
-
-/*
- * Destroy stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
- unsigned i;
-
- PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
- pjmedia_snd_stream_stop(stream);
-
- if (stream->thread)
- {
- SetEvent(stream->thread_quit_event);
- pj_thread_join(stream->thread);
- pj_thread_destroy(stream->thread);
- stream->thread = NULL;
- }
-
- /* Unprepare the headers and close the play device */
- if (stream->play_strm.hWave.Out)
- {
- waveOutReset(stream->play_strm.hWave.Out);
- for (i = 0; i < stream->play_strm.dwMaxBufIdx; ++i)
- waveOutUnprepareHeader(stream->play_strm.hWave.Out,
- &(stream->play_strm.WaveHdr[i]),
- sizeof(WAVEHDR));
- waveOutClose(stream->play_strm.hWave.Out);
- stream->play_strm.hWave.Out = NULL;
- }
-
- /* Close the play event */
- if (stream->play_strm.hEvent)
- {
- CloseHandle(stream->play_strm.hEvent);
- stream->play_strm.hEvent = NULL;
- }
-
- /* Unprepare the headers and close the record device */
- if (stream->rec_strm.hWave.In)
- {
- waveInReset(stream->rec_strm.hWave.In);
- for (i = 0; i < stream->play_strm.dwMaxBufIdx; ++i)
- waveInUnprepareHeader(stream->rec_strm.hWave.In,
- &(stream->rec_strm.WaveHdr[i]),
- sizeof(WAVEHDR));
- waveInClose(stream->rec_strm.hWave.In);
- stream->rec_strm.hWave.In = NULL;
- }
-
- /* Close the record event */
- if (stream->rec_strm.hEvent)
- {
- CloseHandle(stream->rec_strm.hEvent);
- stream->rec_strm.hEvent = NULL;
- }
-
- pj_pool_release(stream->pool);
-
- return PJ_SUCCESS;
-}
-
-/*
- * Set sound latency.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency,
- unsigned output_latency)
-{
- snd_input_latency = (input_latency == 0)?
- PJMEDIA_SND_DEFAULT_REC_LATENCY : input_latency;
- snd_output_latency = (output_latency == 0)?
- PJMEDIA_SND_DEFAULT_PLAY_LATENCY : output_latency;
-
- return PJ_SUCCESS;
-}
-
-#endif /* PJMEDIA_SOUND_IMPLEMENTATION */
-