summaryrefslogtreecommitdiff
path: root/pjmedia
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-08 22:43:39 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-08 22:43:39 +0000
commit66f9158fa3c12ebd3b2d317cf42e461e0b86a6aa (patch)
tree72de866d32ccf5ae9865331f6714646bdc1c00a9 /pjmedia
parent27f0f0680767989e5098c9c20dda46f01c5de4e3 (diff)
Finished new pjmedia rewrite
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@159 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r--pjmedia/build/pjmedia.dsp15
-rw-r--r--pjmedia/include/pjmedia/codec.h504
-rw-r--r--pjmedia/include/pjmedia/endpoint.h131
-rw-r--r--pjmedia/include/pjmedia/errno.h36
-rw-r--r--pjmedia/include/pjmedia/mediamgr.h100
-rw-r--r--pjmedia/include/pjmedia/rtp.h16
-rw-r--r--pjmedia/include/pjmedia/session.h180
-rw-r--r--pjmedia/include/pjmedia/stream.h147
-rw-r--r--pjmedia/include/pjmedia/types.h142
-rw-r--r--pjmedia/src/pjmedia/codec.c146
-rw-r--r--pjmedia/src/pjmedia/endpoint.c239
-rw-r--r--pjmedia/src/pjmedia/errno.c9
-rw-r--r--pjmedia/src/pjmedia/g711.c126
-rw-r--r--pjmedia/src/pjmedia/mediamgr.c112
-rw-r--r--pjmedia/src/pjmedia/rtcp.c2
-rw-r--r--pjmedia/src/pjmedia/rtp.c22
-rw-r--r--pjmedia/src/pjmedia/session.c890
-rw-r--r--pjmedia/src/pjmedia/stream.c805
-rw-r--r--pjmedia/src/test/audio_tool.c36
-rw-r--r--pjmedia/src/test/session_test.c4
20 files changed, 1931 insertions, 1731 deletions
diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp
index d8feb969..a7f86a47 100644
--- a/pjmedia/build/pjmedia.dsp
+++ b/pjmedia/build/pjmedia.dsp
@@ -96,19 +96,19 @@ SOURCE=..\src\pjmedia\dsound.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\errno.c
+SOURCE=..\src\pjmedia\endpoint.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\g711.c
+SOURCE=..\src\pjmedia\errno.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\jbuf.c
+SOURCE=..\src\pjmedia\g711.c
# End Source File
# Begin Source File
-SOURCE=..\src\pjmedia\mediamgr.c
+SOURCE=..\src\pjmedia\jbuf.c
# End Source File
# Begin Source File
@@ -142,7 +142,6 @@ SOURCE=..\src\pjmedia\sdp_neg.c
# Begin Source File
SOURCE=..\src\pjmedia\session.c
-# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
@@ -162,15 +161,15 @@ SOURCE=..\include\pjmedia\config.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjmedia\errno.h
+SOURCE=..\include\pjmedia\endpoint.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjmedia\jbuf.h
+SOURCE=..\include\pjmedia\errno.h
# End Source File
# Begin Source File
-SOURCE=..\include\pjmedia\mediamgr.h
+SOURCE=..\include\pjmedia\jbuf.h
# End Source File
# Begin Source File
diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h
index 3069f31c..75135d62 100644
--- a/pjmedia/include/pjmedia/codec.h
+++ b/pjmedia/include/pjmedia/codec.h
@@ -25,6 +25,7 @@
* @brief Codec framework.
*/
+#include <pjmedia/types.h>
#include <pj/list.h>
PJ_BEGIN_DECL
@@ -36,312 +37,393 @@ PJ_BEGIN_DECL
* @{
*/
-/** Top most media type. */
-typedef enum pj_media_type
-{
- /** No type. */
- PJ_MEDIA_TYPE_NONE = 0,
-
- /** The media is audio */
- PJ_MEDIA_TYPE_AUDIO = 1,
-
- /** The media is video. */
- PJ_MEDIA_TYPE_VIDEO = 2,
-
- /** Unknown media type, in this case the name will be specified in
- * encoding_name.
- */
- PJ_MEDIA_TYPE_UNKNOWN = 3,
-
-} pj_media_type;
-
-
-/** Media direction. */
-typedef enum pj_media_dir_t
-{
- /** None */
- PJ_MEDIA_DIR_NONE = 0,
-
- /** Encoding (outgoing to network) stream */
- PJ_MEDIA_DIR_ENCODING = 1,
-
- /** Decoding (incoming from network) stream. */
- PJ_MEDIA_DIR_DECODING = 2,
-
- /** Incoming and outgoing stream. */
- PJ_MEDIA_DIR_ENCODING_DECODING = 3,
-} pj_media_dir_t;
-
-
-/** Standard RTP paylist types. */
-typedef enum pj_rtp_pt
-{
- PJ_RTP_PT_PCMU = 0, /* audio PCMU */
- PJ_RTP_PT_GSM = 3, /* audio GSM */
- PJ_RTP_PT_G723 = 4, /* audio G723 */
- PJ_RTP_PT_DVI4_8K = 5, /* audio DVI4 8KHz */
- PJ_RTP_PT_DVI4_16K = 6, /* audio DVI4 16Khz */
- PJ_RTP_PT_LPC = 7, /* audio LPC */
- PJ_RTP_PT_PCMA = 8, /* audio PCMA */
- PJ_RTP_PT_G722 = 9, /* audio G722 */
- PJ_RTP_PT_L16_2 = 10, /* audio 16bit linear 44.1KHz stereo */
- PJ_RTP_PT_L16_1 = 11, /* audio 16bit linear 44.1KHz mono */
- PJ_RTP_PT_QCELP = 12, /* audio QCELP */
- PJ_RTP_PT_CN = 13, /* audio Comfort Noise */
- PJ_RTP_PT_MPA = 14, /* audio MPEG1 or MPEG2 as elementary streams */
- PJ_RTP_PT_G728 = 15, /* audio G728 */
- PJ_RTP_PT_DVI4_11K = 16, /* audio DVI4 11.025KHz mono */
- PJ_RTP_PT_DVI4_22K = 17, /* audio DVI4 22.050KHz mono */
- PJ_RTP_PT_G729 = 18, /* audio G729 */
- PJ_RTP_PT_CELB = 25, /* video/comb Cell-B by Sun Microsystems (RFC 2029) */
- PJ_RTP_PT_JPEG = 26, /* video JPEG */
- PJ_RTP_PT_NV = 28, /* video NV implemented by nv program by Xerox */
- PJ_RTP_PT_H261 = 31, /* video H261 */
- PJ_RTP_PT_MPV = 32, /* video MPEG1 or MPEG2 elementary streams */
- PJ_RTP_PT_MP2T = 33, /* video MPEG2 transport */
- PJ_RTP_PT_H263 = 34, /* video H263 */
-
- PJ_RTP_PT_DYNAMIC = 96, /* start of dynamic RTP payload */
-} pj_rtp_pt;
-
-
-/** Identification used to search for codec factory that supports specific
- * codec specification.
+/**
+ * Standard RTP static payload types, as defined by RFC 3551.
*/
-typedef struct pj_codec_id
+enum pjmedia_rtp_pt
{
- /** Media type. */
- pj_media_type type;
+ PJMEDIA_RTP_PT_PCMU = 0, /* audio PCMU */
+ PJMEDIA_RTP_PT_GSM = 3, /* audio GSM */
+ PJMEDIA_RTP_PT_G723 = 4, /* audio G723 */
+ PJMEDIA_RTP_PT_DVI4_8K = 5, /* audio DVI4 8KHz */
+ PJMEDIA_RTP_PT_DVI4_16K = 6, /* audio DVI4 16Khz */
+ PJMEDIA_RTP_PT_LPC = 7, /* audio LPC */
+ PJMEDIA_RTP_PT_PCMA = 8, /* audio PCMA */
+ PJMEDIA_RTP_PT_G722 = 9, /* audio G722 */
+ PJMEDIA_RTP_PT_L16_2 = 10, /* audio 16bit linear 44.1KHz stereo */
+ PJMEDIA_RTP_PT_L16_1 = 11, /* audio 16bit linear 44.1KHz mono */
+ PJMEDIA_RTP_PT_QCELP = 12, /* audio QCELP */
+ PJMEDIA_RTP_PT_CN = 13, /* audio Comfort Noise */
+ PJMEDIA_RTP_PT_MPA = 14, /* audio MPEG1/MPEG2 elementary streams */
+ PJMEDIA_RTP_PT_G728 = 15, /* audio G728 */
+ PJMEDIA_RTP_PT_DVI4_11K = 16, /* audio DVI4 11.025KHz mono */
+ PJMEDIA_RTP_PT_DVI4_22K = 17, /* audio DVI4 22.050KHz mono */
+ PJMEDIA_RTP_PT_G729 = 18, /* audio G729 */
+
+ PJMEDIA_RTP_PT_CELB = 25, /* video/comb Cell-B by Sun (RFC 2029) */
+ PJMEDIA_RTP_PT_JPEG = 26, /* video JPEG */
+ PJMEDIA_RTP_PT_NV = 28, /* video NV by nv program by Xerox */
+ PJMEDIA_RTP_PT_H261 = 31, /* video H261 */
+ PJMEDIA_RTP_PT_MPV = 32, /* video MPEG1 or MPEG2 elementary */
+ PJMEDIA_RTP_PT_MP2T = 33, /* video MPEG2 transport */
+ PJMEDIA_RTP_PT_H263 = 34, /* video H263 */
+
+ PJMEDIA_RTP_PT_DYNAMIC = 96, /* start of dynamic RTP payload */
- /** Payload type (can be dynamic). */
- unsigned pt;
-
- /** Encoding name, must be present if the payload type is dynamic. */
- pj_str_t encoding_name;
-
- /** Sampling rate. */
- unsigned sample_rate;
-} pj_codec_id;
+};
-/** Detailed codec attributes used both to configure a codec and to query
- * the capability of codec factories.
+/**
+ * Identification used to search for codec factory that supports specific
+ * codec specification.
*/
-typedef struct pj_codec_attr
+struct pjmedia_codec_info
{
- pj_uint32_t sample_rate; /* Sampling rate in Hz */
- pj_uint32_t avg_bps; /* Average bandwidth in bits per second */
-
- pj_uint8_t pcm_bits_per_sample;/* Bits per sample in the PCM side */
- pj_uint16_t ptime; /* Packet time in miliseconds */
-
- unsigned pt:8; /* Payload type. */
- unsigned vad_enabled:1; /* Voice Activity Detector. */
- unsigned cng_enabled:1; /* Comfort Noise Generator. */
- unsigned lpf_enabled:1; /* Low pass filter */
- unsigned hpf_enabled:1; /* High pass filter */
- unsigned penh_enabled:1; /* Perceptual Enhancement */
- unsigned concl_enabled:1; /* Packet loss concealment */
- unsigned reserved_bit:1;
+ pjmedia_type type; /**< Media type. */
+ unsigned pt; /**< Payload type (can be dynamic). */
+ pj_str_t encoding_name; /**< Encoding name. */
+ unsigned sample_rate; /**< Sampling rate. */
+};
-} pj_codec_attr;
-/** Types of audio frame. */
-typedef enum pj_audio_frame_type
+/**
+ * Detailed codec attributes used both to configure a codec and to query
+ * the capability of codec factories.
+ */
+struct pjmedia_codec_param
{
- /** The frame is a silence audio frame. */
- PJ_AUDIO_FRAME_SILENCE,
+ pj_uint32_t sample_rate; /**< Sampling rate in Hz */
+ pj_uint32_t avg_bps; /**< Average bandwidth in bits/sec */
- /** The frame is a non-silence audio frame. */
- PJ_AUDIO_FRAME_AUDIO,
+ pj_uint8_t pcm_bits_per_sample;/**< Bits/sample in the PCM side */
+ pj_uint16_t ptime; /**< Packet time in miliseconds */
-} pj_audio_frame_type;
+ unsigned pt:8; /**< Payload type. */
+ unsigned vad_enabled:1; /**< Voice Activity Detector. */
+ unsigned cng_enabled:1; /**< Comfort Noise Generator. */
+ unsigned lpf_enabled:1; /**< Low pass filter */
+ unsigned hpf_enabled:1; /**< High pass filter */
+ unsigned penh_enabled:1; /**< Perceptual Enhancement */
+ unsigned concl_enabled:1; /**< Packet loss concealment */
+ unsigned reserved_bit:1; /**< Reserved, must be NULL. */
-typedef struct pj_codec pj_codec;
-typedef struct pj_codec_factory pj_codec_factory;
+};
-/** This structure describes an audio frame. */
-struct pj_audio_frame
+/**
+ * Types of media frame.
+ */
+enum pjmedia_frame_type
{
- /** Type: silence or non-silence. */
- pj_audio_frame_type type;
+ PJMEDIA_FRAME_TYPE_SILENCE_AUDIO, /**< Silence audio frame. */
+ PJMEDIA_FRAME_TYPE_AUDIO, /**< Normal audio frame. */
- /** Pointer to buffer. */
- void *buf;
+};
- /** Frame size in bytes. */
- unsigned size;
+/**
+ * This structure describes a media frame.
+ */
+struct pjmedia_frame
+{
+ pjmedia_frame_type type; /**< Frame type. */
+ void *buf; /**< Pointer to buffer. */
+ pj_size_t size; /**< Frame size in bytes. */
};
/**
- * Operations that must be supported by the codec.
+ * This structure describes codec operations. Each codec MUST implement
+ * all of these functions.
*/
-typedef struct pj_codec_op
+struct pjmedia_codec_op
{
- /** Get default attributes. */
- pj_status_t (*default_attr) (pj_codec *codec, pj_codec_attr *attr);
-
- /** Open and initialize codec using the specified attribute.
- * @return zero on success.
+ /**
+ * Get default attributes for this codec.
+ *
+ * @param codec The codec instance.
+ * @param attr Pointer to receive default codec attributes.
+ *
+ * @return PJ_SUCCESS on success.
*/
- pj_status_t (*init)( pj_codec *codec, pj_pool_t *pool );
-
- /** Close and shutdown codec.
+ pj_status_t (*default_attr)(pjmedia_codec *codec,
+ pjmedia_codec_param *attr);
+
+ /**
+ * Initialize codec using the specified attribute.
+ *
+ * @param codec The codec instance.
+ * @param pool Pool to use when the codec needs to allocate
+ * some memory.
+ *
+ * @return PJ_SUCCESS on success.
*/
- pj_status_t (*open)( pj_codec *codec, pj_codec_attr *attr );
-
- /** Close and shutdown codec.
+ pj_status_t (*init)(pjmedia_codec *codec,
+ pj_pool_t *pool );
+
+ /**
+ * Open the codec and initialize with the specified parameter..
+ *
+ * @param codec The codec instance.
+ * @param param Codec initialization parameter.
+ *
+ * @return PJ_SUCCESS on success.
*/
- pj_status_t (*close)( pj_codec *codec );
-
- /** Encode frame.
+ pj_status_t (*open)(pjmedia_codec *codec,
+ pjmedia_codec_param *param );
+
+ /**
+ * Close and shutdown codec, releasing all resources allocated by
+ * this codec, if any.
+ *
+ * @param codec The codec instance.
+ *
+ * @return PJ_SUCCESS on success.
*/
- pj_status_t (*encode)( pj_codec *codec, const struct pj_audio_frame *input,
- unsigned output_buf_len, struct pj_audio_frame *output);
-
- /** Decode frame.
+ pj_status_t (*close)(pjmedia_codec *codec);
+
+
+ /**
+ * Instruct the codec to encode the specified input frame.
+ *
+ * @param codec The codec instance.
+ * @param input The input frame.
+ * @param out_size The length of buffer in the output frame.
+ * @param output The output frame.
+ *
+ * @return PJ_SUCCESS on success;
*/
- pj_status_t (*decode)( pj_codec *codec, const struct pj_audio_frame *input,
- unsigned output_buf_len, struct pj_audio_frame *output);
+ pj_status_t (*encode)(pjmedia_codec *codec,
+ const struct pjmedia_frame *input,
+ unsigned out_size,
+ struct pjmedia_frame *output);
+
+ /**
+ * Instruct the codec to decode the specified input frame.
+ *
+ * @param codec The codec instance.
+ * @param input The input frame.
+ * @param out_size The length of buffer in the output frame.
+ * @param output The output frame.
+ *
+ * @return PJ_SUCCESS on success;
+ */
+ pj_status_t (*decode)(pjmedia_codec *codec,
+ const struct pjmedia_frame *input,
+ unsigned out_size,
+ struct pjmedia_frame *output);
+
+};
-} pj_codec_op;
/**
- * A codec describes an instance to encode or decode media frames.
+ * This structure describes a codec instance.
*/
-struct pj_codec
+struct pjmedia_codec
{
/** Entries to put this codec instance in codec factory's list. */
- PJ_DECL_LIST_MEMBER(struct pj_codec);
+ PJ_DECL_LIST_MEMBER(struct pjmedia_codec);
/** Codec's private data. */
void *codec_data;
/** Codec factory where this codec was allocated. */
- pj_codec_factory *factory;
+ pjmedia_codec_factory *factory;
/** Operations to codec. */
- pj_codec_op *op;
+ pjmedia_codec_op *op;
};
+
/**
- * This structure describes operations that must be supported by codec factories.
+ * This structure describes operations that must be supported by codec
+ * factories.
*/
-typedef struct pj_codec_factory_op
+struct pjmedia_codec_factory_op
{
- /** Check whether the factory can create codec with the specified ID.
- * @param factory The codec factory.
- * @param id The codec ID.
- * @return zero it matches.
+ /**
+ * Check whether the factory can create codec with the specified
+ * codec info.
+ *
+ * @param factory The codec factory.
+ * @param info The codec info.
+ *
+ * @return PJ_SUCCESS if this factory is able to create an
+ * instance of codec with the specified info.
*/
- pj_status_t (*match_id)( pj_codec_factory *factory, const pj_codec_id *id );
-
- /** Create default attributes for the specified codec ID. This function can
- * be called by application to get the capability of the codec.
- * @param factory The codec factory.
- * @param id The codec ID.
- * @param attr The attribute to be initialized.
- * @return zero if success.
+ pj_status_t (*test_alloc)(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *info );
+
+ /**
+ * Create default attributes for the specified codec ID. This function
+ * can be called by application to get the capability of the codec.
+ *
+ * @param factory The codec factory.
+ * @param info The codec info.
+ * @param attr The attribute to be initialized.
+ *
+ * @return PJ_SUCCESS if success.
*/
- pj_status_t (*default_attr)( pj_codec_factory *factory, const pj_codec_id *id,
- pj_codec_attr *attr );
-
- /** Enumerate supported codecs.
- * @param factory The codec factory.
- * @param count Number of entries in the array.
- * @param codecs The codec array.
- * @return the total number of supported codecs, which can be less or
- * greater than requested.
+ pj_status_t (*default_attr)(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *info,
+ pjmedia_codec_param *attr );
+
+ /**
+ * Enumerate supported codecs that can be created using this factory.
+ *
+ * @param factory The codec factory.
+ * @param count On input, specifies the number of elements in
+ * the array. On output, the value will be set to
+ * the number of elements that have been initialized
+ * by this function.
+ * @param info The codec info array, which contents will be
+ * initialized upon return.
+ *
+ * @return PJ_SUCCESS on success.
*/
- unsigned (*enum_codecs) (pj_codec_factory *factory, unsigned count, pj_codec_id codecs[]);
-
- /** This function is called by codec manager to instantiate one codec
- * instance.
- * @param factory The codec factory.
- * @param id The codec ID.
- * @return the instance of the codec, or NULL if codec can not be created.
+ pj_status_t (*enum_info)(pjmedia_codec_factory *factory,
+ unsigned *count,
+ pjmedia_codec_info codecs[]);
+
+ /**
+ * Create one instance of the codec with the specified codec info.
+ *
+ * @param factory The codec factory.
+ * @param info The codec info.
+ * @param p_codec Pointer to receive the codec instance.
+ *
+ * @return PJ_SUCCESS on success.
*/
- pj_codec* (*alloc_codec)( pj_codec_factory *factory, const pj_codec_id *id);
-
- /** This function is called by codec manager to return a particular instance
- * of codec back to the codec factory.
- * @param factory The codec factory.
- * @param codec The codec instance to be returned.
+ pj_status_t (*alloc_codec)(pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *info,
+ pjmedia_codec **p_codec);
+
+ /**
+ * This function is called by codec manager to return a particular
+ * instance of codec back to the codec factory.
+ *
+ * @param factory The codec factory.
+ * @param codec The codec instance to be returned.
+ *
+ * @return PJ_SUCCESS on success.
*/
- void (*dealloc_codec)( pj_codec_factory *factory, pj_codec *codec );
+ pj_status_t (*dealloc_codec)(pjmedia_codec_factory *factory,
+ pjmedia_codec *codec );
+
+};
-} pj_codec_factory_op;
/**
* Codec factory describes a module that is able to create codec with specific
* capabilities. These capabilities can be queried by codec manager to create
* instances of codec.
*/
-struct pj_codec_factory
+struct pjmedia_codec_factory
{
/** Entries to put this structure in the codec manager list. */
- PJ_DECL_LIST_MEMBER(struct pj_codec_factory);
+ PJ_DECL_LIST_MEMBER(struct pjmedia_codec_factory);
/** The factory's private data. */
- void *factory_data;
+ void *factory_data;
/** Operations to the factory. */
- pj_codec_factory_op *op;
+ pjmedia_codec_factory_op *op;
};
/**
* Declare maximum codecs
*/
-#define PJ_CODEC_MGR_MAX_CODECS 32
+#define PJMEDIA_CODEC_MGR_MAX_CODECS 32
/**
* Codec manager maintains codec factory etc.
*/
-typedef struct pj_codec_mgr
+typedef struct pjmedia_codec_mgr
{
- pj_codec_factory factory_list;
- unsigned codec_cnt;
- pj_codec_id codecs[PJ_CODEC_MGR_MAX_CODECS];
-} pj_codec_mgr;
+ pjmedia_codec_factory factory_list;
+ unsigned codec_cnt;
+ pjmedia_codec_info codecs[PJMEDIA_CODEC_MGR_MAX_CODECS];
+} pjmedia_codec_mgr;
+
+
/**
- * Init codec manager.
+ * Initialize codec manager.
+ *
+ * @param mgr Codec manager instance.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t)
-pj_codec_mgr_init (pj_codec_mgr *mgr);
+PJ_DECL(pj_status_t) pjmedia_codec_mgr_init(pjmedia_codec_mgr *mgr);
+
/**
- * Register codec to codec manager.
+ * Register codec factory to codec manager.
+ *
+ * @param mgr The codec manager.
+ * @param factory The codec factory to be registered.
+ *
+ * @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t)
-pj_codec_mgr_register_factory (pj_codec_mgr *mgr, pj_codec_factory *factory);
+pjmedia_codec_mgr_register_factory( pjmedia_codec_mgr *mgr,
+ pjmedia_codec_factory *factory);
/**
- * Unregister codec.
+ * Unregister codec factory from the codec manager.
+ *
+ * @param mgr The codec manager.
+ * @param factory The codec factory to be unregistered.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(void)
-pj_codec_mgr_unregister_factory (pj_codec_mgr *mgr, pj_codec_factory *factory);
+PJ_DECL(pj_status_t)
+pjmedia_codec_mgr_unregister_factory( pjmedia_codec_mgr *mgr,
+ pjmedia_codec_factory *factory);
/**
- * Enumerate codecs.
+ * Enumerate all supported codec.
+ *
+ * @param mgr The codec manager.
+ * @param count On input, specifies the number of elements in
+ * the array. On output, the value will be set to
+ * the number of elements that have been initialized
+ * by this function.
+ * @param info The codec info array, which contents will be
+ * initialized upon return.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(unsigned)
-pj_codec_mgr_enum_codecs (pj_codec_mgr *mgr, unsigned count, const pj_codec_id *codecs[]);
+PJ_DECL(pj_status_t) pjmedia_codec_mgr_enum_codecs( pjmedia_codec_mgr *mgr,
+ unsigned *count,
+ pjmedia_codec_info info[]);
/**
- * Open codec.
+ * Request the codec manager to allocate one instance of codec with the
+ * specified codec info. The codec will enumerate all codec factories
+ * until it finds factory that is able to create the specified codec.
+ *
+ * @param mgr The codec manager.
+ * @param info The information about the codec to be created.
+ * @param p_codec Pointer to receive the codec instance.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_codec*)
-pj_codec_mgr_alloc_codec (pj_codec_mgr *mgr, const struct pj_codec_id *id);
+PJ_DECL(pj_status_t) pjmedia_codec_mgr_alloc_codec(pjmedia_codec_mgr *mgr,
+ const pjmedia_codec_info *info,
+ pjmedia_codec **p_codec);
/**
- * Close codec.
+ * Deallocate the specified codec instance. The codec manager will return
+ * the instance of the codec back to its factory.
+ *
+ * @param mgr The codec manager.
+ * @param codec The codec instance.
+ *
+ * @return PJ_SUCESS on success.
*/
-PJ_DECL(void)
-pj_codec_mgr_dealloc_codec (pj_codec_mgr *mgr, pj_codec *codec);
+PJ_DECL(pj_status_t) pjmedia_codec_mgr_dealloc_codec(pjmedia_codec_mgr *mgr,
+ pjmedia_codec *codec);
/**
* @}
diff --git a/pjmedia/include/pjmedia/endpoint.h b/pjmedia/include/pjmedia/endpoint.h
new file mode 100644
index 00000000..27e8f4bf
--- /dev/null
+++ b/pjmedia/include/pjmedia/endpoint.h
@@ -0,0 +1,131 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJMEDIA_MEDIAMGR_H__
+#define __PJMEDIA_MEDIAMGR_H__
+
+
+/**
+ * @file mediamgr.h
+ * @brief Media Manager.
+ */
+/**
+ * @defgroup PJMED_ENDPT Media Endpoint
+ * @ingroup PJMEDIA
+ * @{
+ *
+ * The media endpoint acts as placeholder for endpoint capabilities. Each
+ * media endpoint will have a codec manager to manage list of codecs installed
+ * in the endpoint and a sound device factory.
+ *
+ * A reference to media endpoint instance is required when application wants
+ * to create a media session (#pj_media_session_create or
+ * #pj_media_session_create_from_sdp).
+ */
+
+#include <pjmedia/sound.h>
+#include <pjmedia/codec.h>
+
+
+PJ_BEGIN_DECL
+
+
+
+/**
+ * Create an instance of media endpoint.
+ *
+ * @param pf Pool factory, which will be used by the media endpoint
+ * throughout its lifetime.
+ * @param p_endpt Pointer to receive the endpoint instance.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_endpt_create( pj_pool_factory *pf,
+ pjmedia_endpt **p_endpt);
+
+/**
+ * Destroy media endpoint instance.
+ *
+ * @param endpt Media endpoint instance.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_endpt_destroy(pjmedia_endpt *endpt);
+
+
+/**
+ * Request the media endpoint to create pool.
+ *
+ * @param endpt The media endpoint instance.
+ * @param name Name to be assigned to the pool.
+ * @param initial Initial pool size, in bytes.
+ * @param increment Increment size, in bytes.
+ *
+ * @return Memory pool.
+ */
+PJ_DECL(pj_pool_t*) pjmedia_endpt_create_pool( pjmedia_endpt *endpt,
+ const char *name,
+ pj_size_t initial,
+ pj_size_t increment);
+
+/**
+ * Get the codec manager instance of the media endpoint.
+ *
+ * @param endpt The media endpoint instance.
+ *
+ * @return The instance of codec manager belonging to
+ * this media endpoint.
+ */
+PJ_DECL(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *mgr);
+
+
+/**
+ * Create a SDP session description that describes the endpoint
+ * capability.
+ *
+ * @param endpt The media endpoint.
+ * @param pool Pool to use to create the SDP descriptor.
+ * @param stream_cnt Number of elements in the sock_info array. This
+ * also denotes the maximum number of streams (i.e.
+ * the "m=" lines) that will be created in the SDP.
+ * @param sock_info Array of socket transport information. One
+ * transport is needed for each media stream, and
+ * each transport consists of an RTP and RTCP socket
+ * pair.
+ * @param p_sdp Pointer to receive SDP session descriptor.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
+ pj_pool_t *pool,
+ unsigned stream_cnt,
+ const pjmedia_sock_info sock_info[],
+ pjmedia_sdp_session **p_sdp );
+
+
+
+PJ_END_DECL
+
+
+/**
+ * @}
+ */
+
+
+
+#endif /* __PJMEDIA_MEDIAMGR_H__ */
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index 14da37de..8d1f6e14 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -259,6 +259,42 @@ PJ_DECL(pj_str_t) pjmedia_strerror( pj_status_t status, char *buffer,
#define PJMEDIA_SDP_ETIMENOTEQUAL (PJMEDIA_ERRNO_START+72) /* 220072 */
+/************************************************************
+ * CODEC
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Unsupported codec.
+ */
+#define PJMEDIA_CODEC_EUNSUP (PJMEDIA_ERRNO_START+80) /* 220080 */
+
+
+/************************************************************
+ * MEDIA
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Invalid remote IP address (in SDP).
+ */
+#define PJMEDIA_EINVALIDIP (PJMEDIA_ERRNO_START+100) /* 220100 */
+/**
+ * @hideinitializer
+ * Asymetric codec is not supported.
+ */
+#define PJMEDIA_EASYMCODEC (PJMEDIA_ERRNO_START+101) /* 220101 */
+/**
+ * @hideinitializer
+ * Invalid payload type.
+ */
+#define PJMEDIA_EINVALIDPT (PJMEDIA_ERRNO_START+102) /* 220102 */
+/**
+ * @hideinitializer
+ * Missing rtpmap.
+ */
+#define PJMEDIA_EMISSINGRTPMAP (PJMEDIA_ERRNO_START+103) /* 220103 */
+
+
+
PJ_END_DECL
#endif /* __PJMEDIA_ERRNO_H__ */
diff --git a/pjmedia/include/pjmedia/mediamgr.h b/pjmedia/include/pjmedia/mediamgr.h
deleted file mode 100644
index 148038ec..00000000
--- a/pjmedia/include/pjmedia/mediamgr.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __PJMEDIA_MEDIAMGR_H__
-#define __PJMEDIA_MEDIAMGR_H__
-
-
-/**
- * @file mediamgr.h
- * @brief Media Manager.
- */
-/**
- * @defgroup PJMED_MGR Media Manager
- * @ingroup PJMEDIA
- * @{
- *
- * The media manager acts as placeholder for endpoint capabilities. Each
- * media manager will have a codec manager to manage list of codecs installed
- * in the endpoint and a sound device factory.
- *
- * A reference to media manager instance is required when application wants
- * to create a media session (#pj_media_session_create or
- * #pj_media_session_create_from_sdp).
- */
-
-#include <pjmedia/sound.h>
-#include <pjmedia/codec.h>
-
-
-PJ_BEGIN_DECL
-
-
-/** Opague declaration of media manager. */
-typedef struct pj_med_mgr_t pj_med_mgr_t;
-
-/**
- * Create an instance of media manager.
- *
- * @param pf Pool factory.
- * @param conn_addr Connection address to be used by this media manager.
- *
- * @return A new instance of media manager, or NULL if failed.
- */
-PJ_DECL(pj_med_mgr_t*) pj_med_mgr_create (pj_pool_factory *pf);
-
-/**
- * Destroy media manager instance.
- *
- * @param mgr Media manager instance.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pj_med_mgr_destroy (pj_med_mgr_t *mgr);
-
-/**
- * Get pool factory of the media manager as specified when the media
- * manager was created.
- *
- * @param mgr The media manager instance.
- *
- * @return Pool factory instance of the media manager.
- */
-PJ_DECL(pj_pool_factory*) pj_med_mgr_get_pool_factory (pj_med_mgr_t *mgr);
-
-/**
- * Get the codec manager instance.
- *
- * @param mgr The media manager instance.
- *
- * @return The instance of codec manager.
- */
-PJ_DECL(pj_codec_mgr*) pj_med_mgr_get_codec_mgr (pj_med_mgr_t *mgr);
-
-
-
-PJ_END_DECL
-
-
-/**
- * @}
- */
-
-
-
-#endif /* __PJMEDIA_MEDIAMGR_H__ */
diff --git a/pjmedia/include/pjmedia/rtp.h b/pjmedia/include/pjmedia/rtp.h
index 54c1e32e..bbb38f53 100644
--- a/pjmedia/include/pjmedia/rtp.h
+++ b/pjmedia/include/pjmedia/rtp.h
@@ -79,14 +79,14 @@ PJ_BEGIN_DECL
*/
enum pj_rtp_error_t
{
- PJ_RTP_ERR_RTP_PACKING, /**< Invalid RTP packet. */
- PJ_RTP_ERR_INVALID_VERSION, /**< Invalid RTP version. */
- PJ_RTP_ERR_INVALID_SSRC, /**< Invalid SSRC. */
- PJ_RTP_ERR_INVALID_PT, /**< Invalid payload type. */
- PJ_RTP_ERR_INVALID_PACKET, /**< Invalid packet. */
- PJ_RTP_ERR_SESSION_RESTARTED, /**< Session has just been restarted. */
- PJ_RTP_ERR_SESSION_PROBATION, /**< Session in probation. */
- PJ_RTP_ERR_BAD_SEQUENCE, /**< Bad RTP sequence number. */
+ PJMEDIA_RTP_ERR_RTP_PACKING, /**< Invalid RTP packet. */
+ PJMEDIA_RTP_ERR_INVALID_VERSION, /**< Invalid RTP version. */
+ PJMEDIA_RTP_ERR_INVALID_SSRC, /**< Invalid SSRC. */
+ PJMEDIA_RTP_ERR_INVALID_PT, /**< Invalid payload type. */
+ PJMEDIA_RTP_ERR_INVALID_PACKET, /**< Invalid packet. */
+ PJMEDIA_RTP_ERR_SESSION_RESTARTED, /**< Session has just been restarted. */
+ PJMEDIA_RTP_ERR_SESSION_PROBATION, /**< Session in probation. */
+ PJMEDIA_RTP_ERR_BAD_SEQUENCE, /**< Bad RTP sequence number. */
};
#pragma pack(1)
diff --git a/pjmedia/include/pjmedia/session.h b/pjmedia/include/pjmedia/session.h
index d9efeb81..f6a9fc11 100644
--- a/pjmedia/include/pjmedia/session.h
+++ b/pjmedia/include/pjmedia/session.h
@@ -25,8 +25,7 @@
* @brief Media Session.
*/
-#include <pj/types.h>
-#include <pjmedia/mediamgr.h>
+#include <pjmedia/endpoint.h>
#include <pjmedia/stream.h>
#include <pjmedia/sdp.h>
@@ -38,109 +37,140 @@ PJ_BEGIN_DECL
* @{
*/
-/** Opaque declaration of media session. */
-typedef struct pj_media_session_t pj_media_session_t;
-
-/** Media socket info. */
-typedef struct pj_media_sock_info
-{
- pj_sock_t rtp_sock, rtcp_sock;
- pj_sockaddr_in rtp_addr_name;
-} pj_media_sock_info;
-
-/** Stream info. */
-typedef struct pj_media_stream_info
-{
- pj_str_t type;
- pj_media_dir_t dir;
- pj_str_t transport;
- pj_media_sock_info sock_info;
- pj_str_t rem_addr;
- unsigned short rem_port;
- unsigned fmt_cnt;
- pj_codec_id fmt[PJSDP_MAX_FMT];
-
-} pj_media_stream_info;
-
-/** Flag for modifying stream. */
-enum
-{
- PJ_MEDIA_STREAM_MODIFY_DIR = 1,
-};
/**
- * Create new session offering.
+ * Create new session offering based on the local and remote SDP.
+ * The session initially will be inactive.
+ *
+ * @param endpt The PJMEDIA endpoint instance.
+ * @param stream_cnt Maximum number of streams to be created. This
+ * also denotes the number of elements in the
+ * socket information.
+ * @param skinfo Array of socket informations. The argument stream_cnt
+ * specifies the number of elements in this array. One
+ * element is needed for each media stream to be
+ * created in the session.
+ * @param local_sdp The SDP describing local capability.
+ * @param rem_sdp The SDP describing remote capability.
+ * @param p_session Pointer to receive the media session.
+ *
+ * @return PJ_SUCCESS if media session can be created
+ * successfully.
*/
-PJ_DECL(pj_media_session_t*)
-pj_media_session_create ( pj_med_mgr_t *mgr, const pj_media_sock_info *skinfo );
+PJ_DECL(pj_status_t) pjmedia_session_create( pjmedia_endpt *endpt,
+ unsigned stream_cnt,
+ const pjmedia_sock_info skinfo[],
+ const pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ pjmedia_session **p_session );
-/**
- * Create new session based on peer's offering.
- */
-PJ_DECL(pj_media_session_t*)
-pj_media_session_create_from_sdp ( pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp,
- const pj_media_sock_info *skinfo);
/**
- * Duplicate session. The new session is inactive.
+ * Activate all streams in media session for the specified direction.
+ *
+ * @param session The media session.
+ * @param dir The direction to activate.
+ *
+ * @return PJ_SUCCESS if success.
*/
-PJ_DECL(pj_media_session_t*)
-pj_media_session_clone (const pj_media_session_t *session);
+PJ_DECL(pj_status_t) pjmedia_session_resume(pjmedia_session *session,
+ pjmedia_dir dir);
-/**
- * Create SDP description from the session.
- */
-PJ_DECL(pjsdp_session_desc*)
-pj_media_session_create_sdp ( const pj_media_session_t *session, pj_pool_t *pool,
- pj_bool_t only_first_fmt);
/**
- * Update session with SDP answer from peer. The session must NOT active.
+ * Suspend receipt and transmission of all streams in media session
+ * for the specified direction.
+ *
+ * @param session The media session.
+ * @param dir The media direction to suspend.
+ *
+ * @return PJ_SUCCESS if success.
*/
-PJ_DECL(pj_status_t)
-pj_media_session_update ( pj_media_session_t *session,
- const pjsdp_session_desc *sdp);
+PJ_DECL(pj_status_t) pjmedia_session_pause(pjmedia_session *session,
+ pjmedia_dir dir);
/**
- * Enumerate media streams in the session.
- * @return the actual number of streams.
+ * Suspend receipt and transmission of individual stream in media session
+ * for the specified direction.
+ *
+ * @param session The media session.
+ * @param index The stream index.
+ * @param dir The media direction to pause.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(unsigned)
-pj_media_session_enum_streams (const pj_media_session_t *session,
- unsigned count, const pj_media_stream_info *info[]);
+PJ_DECL(pj_status_t) pjmedia_session_pause_stream( pjmedia_session *session,
+ unsigned index,
+ pjmedia_dir dir);
/**
- * Get stream statistics.
+ * Activate individual stream in media session for the specified direction.
+ *
+ * @param session The media session.
+ * @param index The stream index.
+ * @param dir The media direction to activate.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t)
-pj_media_session_get_stat (const pj_media_session_t *session, unsigned index,
- pj_media_stream_stat *tx_stat,
- pj_media_stream_stat *rx_stat);
+PJ_DECL(pj_status_t) pjmedia_session_resume_stream(pjmedia_session *session,
+ unsigned index,
+ pjmedia_dir dir);
/**
- * Modify stream, only when stream is inactive.
+ * Enumerate media streams in the session.
+ *
+ * @param session The media session.
+ * @param count On input, specifies the number of elements in
+ * the array. On output, the number will be filled
+ * with number of streams in the session.
+ * @param strm_info Array of stream info.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t)
-pj_media_session_modify_stream (pj_media_session_t *session, unsigned index,
- unsigned modify_flag, const pj_media_stream_info *info);
+PJ_DECL(pj_status_t) pjmedia_session_enum_streams(const pjmedia_session *session,
+ unsigned *count,
+ pjmedia_stream_info strm_info[]);
+
/**
- * Activate all streams in media session.
+ * Get session statistics. The stream statistic shows various
+ * indicators such as packet count, packet lost, jitter, delay, etc.
+ *
+ * @param session The media session.
+ * @param count On input, specifies the number of elements in
+ * the array. On output, the number will be filled
+ * with number of streams in the session.
+ * @param stat Array of stream statistics.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t)
-pj_media_session_activate (pj_media_session_t *session);
+PJ_DECL(pj_status_t) pjmedia_session_get_stat(const pjmedia_session *session,
+ unsigned *count,
+ pjmedia_stream_stat stat[]);
/**
- * Activate individual stream in media session.
+ * Get individual stream statistics. The stream statistic shows various
+ * indicators such as packet count, packet lost, jitter, delay, etc.
+ *
+ * @param s The media session.
+ * @param index The stream index.
+ * @param stat Stream statistics.
+ *
+ * @return PJ_SUCCESS on success.
*/
-PJ_DECL(pj_status_t)
-pj_media_session_activate_stream (pj_media_session_t *session, unsigned index);
+PJ_DECL(pj_status_t) pjmedia_session_get_stream_stat(const pjmedia_session *s,
+ unsigned index,
+ pjmedia_stream_stat *stat);
/**
* Destroy media session.
+ *
+ * @param session The media session.
+ *
+ * @return PJ_SUCCESS if success.
*/
-PJ_DECL(pj_status_t)
-pj_media_session_destroy (pj_media_session_t *session);
+PJ_DECL(pj_status_t) pjmedia_session_destroy(pjmedia_session *session);
+
/**
diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h
index 09f6acf1..83f7e14e 100644
--- a/pjmedia/include/pjmedia/stream.h
+++ b/pjmedia/include/pjmedia/stream.h
@@ -27,7 +27,7 @@
#include <pjmedia/sound.h>
#include <pjmedia/codec.h>
-#include <pjmedia/mediamgr.h>
+#include <pjmedia/endpoint.h>
#include <pj/sock.h>
PJ_BEGIN_DECL
@@ -39,55 +39,124 @@ PJ_BEGIN_DECL
* @{
*/
-typedef struct pj_media_stream_t pj_media_stream_t;
+/**
+ * Opaque declaration for media channel.
+ * Media channel is unidirectional flow of media from sender to
+ * receiver.
+ */
+typedef struct pjmedia_channel pjmedia_channel;
-/** Parameter for creating channel. */
-typedef struct pj_media_stream_create_param
+/**
+ * This structure describes media stream information. Each media stream
+ * corresponds to one "m=" line in SDP session descriptor, and it has
+ * its own RTP/RTCP socket pair.
+ */
+struct pjmedia_stream_info
{
- /** Codec ID, must NOT be NULL. */
- pj_codec_id *codec_id;
+ pjmedia_type type; /**< Media type (audio, video) */
+ pjmedia_dir dir; /**< Media direction. */
+ pjmedia_sock_info sock_info; /**< Media transport (RTP/RTCP sockets) */
+ pj_sockaddr_in rem_addr; /**< Remote RTP address */
+ pjmedia_codec_info fmt; /**< Codec format info. */
+ pj_uint32_t ssrc; /**< RTP SSRC. */
+ int jb_min; /**< Jitter buffer min delay. */
+ int jb_max; /**< Jitter buffer max delay. */
+ int jb_maxcnt; /**< Jitter buffer max delay. */
+};
- /** Media manager, must NOT be NULL. */
- pj_med_mgr_t *mediamgr;
- /** Direction: IN_OUT, or IN only, or OUT only. */
- pj_media_dir_t dir;
+/**
+ * Individual channel statistic.
+ */
+struct pjmedia_channel_stat
+{
+ pj_uint32_t pkt; /**< Total number of packets. */
+ pj_uint32_t bytes; /**< Total number of bytes, including RTP hdr. */
+ pj_uint32_t lost; /**< Total number of packet lost */
+};
- /** RTP socket. */
- pj_sock_t rtp_sock;
+/**
+ * Stream statistic.
+ */
+struct pjmedia_stream_stat
+{
+ pjmedia_channel_stat enc; /**< Encoder statistics. */
+ pjmedia_channel_stat dec; /**< Decoder statistics. */
+};
- /** RTCP socket. */
- pj_sock_t rtcp_sock;
- /** Address of remote */
- pj_sockaddr_in *remote_addr;
+/**
+ * Create a media stream based on the specified stream parameter.
+ * All channels in the stream initially will be inactive.
+ *
+ * @param endpt Media endpoint.
+ * @param pool Pool to allocate memory for the stream. A large
+ * number of memory may be needed because jitter
+ * buffer needs to preallocate some storage.
+ * @param info Stream information.
+ * @param p_stream Pointer to receive the media stream.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_create(pjmedia_endpt *endpt,
+ pj_pool_t *pool,
+ const pjmedia_stream_info *info,
+ pjmedia_stream **p_stream);
- /** RTP SSRC */
- pj_uint32_t ssrc;
+/**
+ * Destroy the media stream.
+ *
+ * @param stream The media stream.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_destroy(pjmedia_stream *stream);
- /** Jitter buffer parameters. */
- int jb_min, jb_max, jb_maxcnt;
+/**
+ * Start the media stream. This will start the appropriate channels
+ * in the media stream, depending on the media direction that was set
+ * when the stream was created.
+ *
+ * @param stream The media stream.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_start(pjmedia_stream *stream);
-} pj_media_stream_create_param;
-typedef struct pj_media_stream_stat
-{
- pj_uint32_t pkt_tx, pkt_rx; /* packets transmitted/received */
- pj_uint32_t oct_tx, oct_rx; /* octets transmitted/received */
- pj_uint32_t jitter; /* receive jitter in ms */
- pj_uint32_t pkt_lost; /* total packet lost count */
-} pj_media_stream_stat;
-
-PJ_DECL(pj_status_t) pj_media_stream_create (pj_pool_t *pool,
- pj_media_stream_t **enc_stream,
- pj_media_stream_t **dec_stream,
- pj_media_stream_create_param *param);
-PJ_DECL(pj_status_t) pj_media_stream_start (pj_media_stream_t *stream);
-PJ_DECL(pj_status_t) pj_media_stream_get_stat (const pj_media_stream_t *stream,
- pj_media_stream_stat *stat);
-PJ_DECL(pj_status_t) pj_media_stream_pause (pj_media_stream_t *stream);
-PJ_DECL(pj_status_t) pj_media_stream_resume (pj_media_stream_t *stream);
-PJ_DECL(pj_status_t) pj_media_stream_destroy (pj_media_stream_t *stream);
+/**
+ * Get the stream statistics.
+ *
+ * @param stream The media stream.
+ * @param stat Media stream statistics.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_get_stat( const pjmedia_stream *stream,
+ pjmedia_stream_stat *stat);
+
+/**
+ * Pause the individual channel in the stream.
+ *
+ * @param channel The media channel.
+ * @param dir Which direction to pause.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_pause( pjmedia_stream *stream,
+ pjmedia_dir dir);
+
+/**
+ * Resume the individual channel in the stream.
+ *
+ * @param channel The media channel.
+ * @param dir Which direction to resume.
+ *
+ * @return PJ_SUCCESS on success;
+ */
+PJ_DECL(pj_status_t) pjmedia_stream_resume(pjmedia_stream *stream,
+ pjmedia_dir dir);
+
/**
* @}
diff --git a/pjmedia/include/pjmedia/types.h b/pjmedia/include/pjmedia/types.h
index 217a001b..6dd44bf7 100644
--- a/pjmedia/include/pjmedia/types.h
+++ b/pjmedia/include/pjmedia/types.h
@@ -20,8 +20,150 @@
#define __PJMEDIA_TYPES_H__
#include <pj/types.h>
+#include <pj/sock.h>
+/**
+ * Top most media type.
+ */
+enum pjmedia_type
+{
+ /** No type. */
+ PJMEDIA_TYPE_NONE = 0,
+
+ /** The media is audio */
+ PJMEDIA_TYPE_AUDIO = 1,
+
+ /** The media is video. */
+ PJMEDIA_TYPE_VIDEO = 2,
+
+ /** Unknown media type, in this case the name will be specified in
+ * encoding_name.
+ */
+ PJMEDIA_TYPE_UNKNOWN = 3,
+
+};
+
+
+/**
+ * Media direction.
+ */
+enum pjmedia_dir
+{
+ /** None */
+ PJMEDIA_DIR_NONE = 0,
+
+ /** Encoding (outgoing to network) stream */
+ PJMEDIA_DIR_ENCODING = 1,
+
+ /** Decoding (incoming from network) stream. */
+ PJMEDIA_DIR_DECODING = 2,
+
+ /** Incoming and outgoing stream. */
+ PJMEDIA_DIR_ENCODING_DECODING = 3,
+
+};
+
+
+/**
+ * Top level media type.
+ */
+typedef enum pjmedia_type pjmedia_type;
+
+/**
+ * Media direction.
+ */
+typedef enum pjmedia_dir pjmedia_dir;
+
+/**
+ * Codec info.
+ */
+typedef struct pjmedia_codec_info pjmedia_codec_info;
+
+/**
+ * Codec initialization parameter.
+ */
+typedef struct pjmedia_codec_param pjmedia_codec_param;
+
+/**
+ * Types of media frames.
+ */
+typedef enum pjmedia_frame_type pjmedia_frame_type;
+
+/**
+ * This structure describes a media frame.
+ */
+typedef struct pjmedia_frame pjmedia_frame;
+
+/**
+ * Codec instance.
+ */
+typedef struct pjmedia_codec pjmedia_codec;
+
+/**
+ * Codec factory.
+ */
+typedef struct pjmedia_codec_factory pjmedia_codec_factory;
+
+/**
+ * Codec operation.
+ */
+typedef struct pjmedia_codec_op pjmedia_codec_op;
+
+/**
+ * Codec factory operation.
+ */
+typedef struct pjmedia_codec_factory_op pjmedia_codec_factory_op;
+
+/**
+ * Codec manager.
+ */
+typedef struct pjmedia_codec_mgr pjmedia_codec_mgr;
+
+/**
+ * Opague declaration of media endpoint.
+ */
+typedef struct pjmedia_endpt pjmedia_endpt;
+
+
+/**
+ * Media socket info.
+ */
+typedef struct pjmedia_sock_info
+{
+
+ pj_sock_t rtp_sock;
+ pj_sock_t rtcp_sock;
+ pj_sockaddr_in rtp_addr_name;
+
+} pjmedia_sock_info;
+
+
+/**
+ * Typedef for media stream information.
+ */
+typedef struct pjmedia_stream_info pjmedia_stream_info;
+
+/**
+ * Typedef for media stream statistic.
+ */
+typedef struct pjmedia_stream_stat pjmedia_stream_stat;
+
+/**
+ * Typedef for media stream.
+ */
+typedef struct pjmedia_stream pjmedia_stream;
+
+/**
+ * Individual channel statistic.
+ */
+typedef struct pjmedia_channel_stat pjmedia_channel_stat;
+
+/**
+ * Opaque declaration of media session.
+ */
+typedef struct pjmedia_session pjmedia_session;
+
/**
* Forward declaration for SDP attribute (sdp.h)
*/
diff --git a/pjmedia/src/pjmedia/codec.c b/pjmedia/src/pjmedia/codec.c
index a87c301c..2d60d287 100644
--- a/pjmedia/src/pjmedia/codec.c
+++ b/pjmedia/src/pjmedia/codec.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjmedia/codec.h>
+#include <pjmedia/errno.h>
#include <pj/pool.h>
#include <pj/string.h>
#include <pj/assert.h>
@@ -24,84 +25,137 @@
#define THIS_FILE "codec.c"
-static void enum_all_codecs (pj_codec_mgr *cm)
+/*
+ * Reinitialize array of supported codecs.
+ */
+static void enum_all_codecs (pjmedia_codec_mgr *mgr)
{
- pj_codec_factory *cf;
-
- cf = cm->factory_list.next;
- cm->codec_cnt = 0;
- while (cf != &cm->factory_list) {
- pj_codec_id temp[PJ_CODEC_MGR_MAX_CODECS];
- int i, cnt;
-
- cnt = cf->op->enum_codecs (cf, PJ_CODEC_MGR_MAX_CODECS, temp);
- if (cnt > PJ_CODEC_MGR_MAX_CODECS) {
- pj_assert(0);
- PJ_LOG(4, (THIS_FILE, "Too many codecs reported by factory"));
- cnt = PJ_CODEC_MGR_MAX_CODECS;
- }
+ pjmedia_codec_factory *factory;
- for (i=0; i<cnt && cm->codec_cnt < PJ_CODEC_MGR_MAX_CODECS; ++i) {
- cm->codecs[cm->codec_cnt++] = temp[i];
- }
+ mgr->codec_cnt = 0;
- cf = cf->next;
+ factory = mgr->factory_list.next;
+ while (factory != &mgr->factory_list) {
+ unsigned count;
+ pj_status_t status;
+
+ count = PJ_ARRAY_SIZE(mgr->codecs) - mgr->codec_cnt;
+ status = factory->op->enum_info(factory, &count,
+ mgr->codecs+mgr->codec_cnt);
+ if (status == PJ_SUCCESS)
+ mgr->codec_cnt += count;
+
+ factory = factory->next;
}
}
-PJ_DEF(pj_status_t) pj_codec_mgr_init (pj_codec_mgr *mgr)
+/*
+ * Initialize codec manager.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_mgr_init (pjmedia_codec_mgr *mgr)
{
+ PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
+
pj_list_init (&mgr->factory_list);
mgr->codec_cnt = 0;
- return 0;
+
+ return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pj_codec_mgr_register_factory (pj_codec_mgr *mgr,
- pj_codec_factory *factory)
+/*
+ * Register a codec factory.
+ */
+PJ_DEF(pj_status_t)
+pjmedia_codec_mgr_register_factory( pjmedia_codec_mgr *mgr,
+ pjmedia_codec_factory *factory)
{
- pj_list_insert_before (&mgr->factory_list, factory);
+ PJ_ASSERT_RETURN(mgr && factory, PJ_EINVAL);
+
+ pj_list_push_back(&mgr->factory_list, factory);
enum_all_codecs (mgr);
- return 0;
+
+ return PJ_SUCCESS;
}
-PJ_DEF(void) pj_codec_mgr_unregister_factory (pj_codec_mgr *mgr, pj_codec_factory *factory)
+/*
+ * Unregister a codec factory.
+ */
+PJ_DEF(pj_status_t)
+pjmedia_codec_mgr_unregister_factory(pjmedia_codec_mgr *mgr,
+ pjmedia_codec_factory *factory)
{
- PJ_UNUSED_ARG(mgr);
+
+ PJ_ASSERT_RETURN(mgr && factory, PJ_EINVAL);
+
+ /* Factory must be registered. */
+ PJ_ASSERT_RETURN(pj_list_find_node(&mgr->factory_list, factory)==factory,
+ PJ_ENOTFOUND);
+
+
pj_list_erase(factory);
enum_all_codecs (mgr);
+
+ return PJ_SUCCESS;
}
-PJ_DEF(unsigned)
-pj_codec_mgr_enum_codecs (pj_codec_mgr *mgr, unsigned count, const pj_codec_id *codecs[])
+/*
+ * Enum all codecs.
+ */
+PJ_DEF(pj_status_t)
+pjmedia_codec_mgr_enum_codecs(pjmedia_codec_mgr *mgr,
+ unsigned *count,
+ pjmedia_codec_info codecs[])
{
- unsigned i;
-
- if (count > mgr->codec_cnt)
- count = mgr->codec_cnt;
+ PJ_ASSERT_RETURN(mgr && count && codecs, PJ_EINVAL);
- for (i=0; i<count; ++i)
- codecs[i] = &mgr->codecs[i];
+ if (*count > mgr->codec_cnt)
+ *count = mgr->codec_cnt;
+
+ pj_memcpy(codecs, mgr->codecs, *count * sizeof(pjmedia_codec_info));
- return mgr->codec_cnt;
+ return PJ_SUCCESS;
}
-PJ_DEF(pj_codec*) pj_codec_mgr_alloc_codec (pj_codec_mgr *mgr, const struct pj_codec_id *id)
+/*
+ * Allocate one codec.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_mgr_alloc_codec(pjmedia_codec_mgr *mgr,
+ const pjmedia_codec_info *info,
+ pjmedia_codec **p_codec)
{
- pj_codec_factory *factory = mgr->factory_list.next;
+ pjmedia_codec_factory *factory;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(mgr && info && p_codec, PJ_EINVAL);
+
+ *p_codec = NULL;
+
+ factory = mgr->factory_list.next;
while (factory != &mgr->factory_list) {
- if ( (*factory->op->match_id)(factory, id) == 0 ) {
- pj_codec *codec = (*factory->op->alloc_codec)(factory, id);
- if (codec != NULL)
- return codec;
+
+ if ( (*factory->op->test_alloc)(factory, info) == PJ_SUCCESS ) {
+
+ status = (*factory->op->alloc_codec)(factory, info, p_codec);
+ if (status == PJ_SUCCESS)
+ return PJ_SUCCESS;
+
}
+
factory = factory->next;
}
- return NULL;
+
+
+ return PJMEDIA_CODEC_EUNSUP;
}
-PJ_DEF(void) pj_codec_mgr_dealloc_codec (pj_codec_mgr *mgr, pj_codec *codec)
+/*
+ * Dealloc codec.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_mgr_dealloc_codec(pjmedia_codec_mgr *mgr,
+ pjmedia_codec *codec)
{
- PJ_UNUSED_ARG(mgr);
- (*codec->factory->op->dealloc_codec)(codec->factory, codec);
+ PJ_ASSERT_RETURN(mgr && codec, PJ_EINVAL);
+
+ return (*codec->factory->op->dealloc_codec)(codec->factory, codec);
}
diff --git a/pjmedia/src/pjmedia/endpoint.c b/pjmedia/src/pjmedia/endpoint.c
new file mode 100644
index 00000000..0100bd3f
--- /dev/null
+++ b/pjmedia/src/pjmedia/endpoint.c
@@ -0,0 +1,239 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjmedia/endpoint.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/sdp.h>
+#include <pj/sock.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+
+
+#define THIS_FILE "endpoint.c"
+
+static const pj_str_t STR_AUDIO = { "audio", 5};
+static const pj_str_t STR_VIDEO = { "video", 5};
+static const pj_str_t STR_IN = { "IN", 2 };
+static const pj_str_t STR_IP4 = { "IP4", 3};
+static const pj_str_t STR_RTP_AVP = { "RTP/AVP", 7 };
+static const pj_str_t STR_SDP_NAME = { "pjmedia", 7 };
+static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
+
+
+PJ_DECL(pj_status_t) g711_init_factory (pjmedia_codec_factory *factory, pj_pool_t *pool);
+PJ_DECL(pj_status_t) g711_deinit_factory (pjmedia_codec_factory *factory);
+
+
+/** Concrete declaration of media endpoint. */
+struct pjmedia_endpt
+{
+ /** Pool. */
+ pj_pool_t *pool;
+
+ /** Pool factory. */
+ pj_pool_factory *pf;
+
+ /** Codec manager. */
+ pjmedia_codec_mgr codec_mgr;
+};
+
+/**
+ * Initialize and get the instance of media endpoint.
+ */
+PJ_DEF(pj_status_t) pjmedia_endpt_create(pj_pool_factory *pf,
+ pjmedia_endpt **p_endpt)
+{
+ pj_pool_t *pool;
+ pjmedia_endpt *endpt;
+ pjmedia_codec_factory *factory;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(pf && p_endpt, PJ_EINVAL);
+
+ pool = pj_pool_create(pf, "med-ept", 512, 512, NULL);
+ if (!pool)
+ return PJ_ENOMEM;
+
+ endpt = pj_pool_zalloc(pool, sizeof(struct pjmedia_endpt));
+ endpt->pool = pool;
+ endpt->pf = pf;
+
+ /* Sound */
+ pj_snd_init(pf);
+
+ /* Init codec manager. */
+ status = pjmedia_codec_mgr_init(&endpt->codec_mgr);
+ if (status != PJ_SUCCESS) {
+ pj_snd_deinit();
+ goto on_error;
+ }
+
+ /* Init and register G.711 codec. */
+ factory = pj_pool_alloc (endpt->pool, sizeof(pjmedia_codec_factory));
+
+ status = g711_init_factory (factory, endpt->pool);
+ if (status != PJ_SUCCESS) {
+ pj_snd_deinit();
+ goto on_error;
+ }
+
+ status = pjmedia_codec_mgr_register_factory (&endpt->codec_mgr, factory);
+ if (status != PJ_SUCCESS) {
+ pj_snd_deinit();
+ goto on_error;
+ }
+
+ *p_endpt = endpt;
+ return PJ_SUCCESS;
+
+on_error:
+ pj_pool_release(pool);
+ return status;
+}
+
+/**
+ * Get the codec manager instance.
+ */
+PJ_DEF(pjmedia_codec_mgr*) pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
+{
+ return &endpt->codec_mgr;
+}
+
+/**
+ * Deinitialize media endpoint.
+ */
+PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
+{
+ PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
+
+ endpt->pf = NULL;
+
+ pj_snd_deinit();
+ pj_pool_release (endpt->pool);
+
+ return PJ_SUCCESS;
+}
+
+/**
+ * Create pool.
+ */
+PJ_DEF(pj_pool_t*) pjmedia_endpt_create_pool( pjmedia_endpt *endpt,
+ const char *name,
+ pj_size_t initial,
+ pj_size_t increment)
+{
+ pj_assert(endpt != NULL);
+
+ return pj_pool_create(endpt->pf, name, initial, increment, NULL);
+}
+
+/**
+ * Create a SDP session description that describes the endpoint
+ * capability.
+ */
+PJ_DEF(pj_status_t) pjmedia_endpt_create_sdp( pjmedia_endpt *endpt,
+ pj_pool_t *pool,
+ unsigned stream_cnt,
+ const pjmedia_sock_info sock_info[],
+ pjmedia_sdp_session **p_sdp )
+{
+ pj_time_val tv;
+ unsigned i;
+ pjmedia_sdp_session *sdp;
+ pjmedia_sdp_media *m;
+ pjmedia_sdp_attr *attr;
+
+ PJ_ASSERT_RETURN(endpt && pool && p_sdp && stream_cnt, PJ_EINVAL);
+
+
+ /* Create and initialize basic SDP session */
+ sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session));
+
+ pj_gettimeofday(&tv);
+ sdp->origin.user = pj_str("-");
+ sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
+ sdp->origin.net_type = STR_IN;
+ sdp->origin.addr_type = STR_IP4;
+ sdp->origin.addr = *pj_gethostname();
+ sdp->name = STR_SDP_NAME;
+
+ /* Since we only support one media stream at present, put the
+ * SDP connection line in the session level.
+ */
+ sdp->conn = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));
+ sdp->conn->net_type = STR_IN;
+ sdp->conn->addr_type = STR_IP4;
+ pj_strdup2(pool, &sdp->conn->addr,
+ pj_inet_ntoa(sock_info[0].rtp_addr_name.sin_addr));
+
+
+ /* SDP time and attributes. */
+ sdp->time.start = sdp->time.stop = 0;
+ sdp->attr_count = 0;
+
+ /* Create media stream 0: */
+
+ sdp->media_count = 1;
+ m = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_media));
+ sdp->media[0] = m;
+
+ /* Standard media info: */
+ pj_strdup(pool, &m->desc.media, &STR_AUDIO);
+ m->desc.port = pj_ntohs(sock_info[0].rtp_addr_name.sin_port);
+ m->desc.port_count = 1;
+ pj_strdup (pool, &m->desc.transport, &STR_RTP_AVP);
+
+ /* Add format and rtpmap for each codec. */
+ m->desc.fmt_count = 0;
+ m->attr_count = 0;
+
+ for (i=0; i<endpt->codec_mgr.codec_cnt; ++i) {
+
+ pjmedia_codec_info *codec_info = &endpt->codec_mgr.codecs[i];
+ pjmedia_sdp_rtpmap rtpmap;
+ pjmedia_sdp_attr *attr;
+ pj_str_t *fmt = &m->desc.fmt[m->desc.fmt_count++];
+
+ fmt->ptr = pj_pool_alloc(pool, 8);
+ fmt->slen = pj_utoa(codec_info->pt, fmt->ptr);
+
+ rtpmap.pt = *fmt;
+ rtpmap.clock_rate = codec_info->sample_rate;
+ rtpmap.enc_name = codec_info->encoding_name;
+ rtpmap.param.slen = 0;
+
+ pjmedia_sdp_rtpmap_to_attr(pool, &rtpmap, &attr);
+ m->attr[m->attr_count++] = attr;
+
+ }
+
+ /* Add sendrect attribute. */
+ attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr));
+ attr->name = STR_SENDRECV;
+ m->attr[m->attr_count++] = attr;
+
+
+ /* Done */
+ *p_sdp = sdp;
+
+ return PJ_SUCCESS;
+
+}
+
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index e42b5444..aca50aef 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -76,6 +76,15 @@ static const struct
{ PJMEDIA_SDP_EORIGINNOTEQUAL, "SDP origin line not equal" },
{ PJMEDIA_SDP_ENAMENOTEQUAL, "SDP name/subject line not equal" },
{ PJMEDIA_SDP_ETIMENOTEQUAL, "SDP time line not equal" },
+
+ /* Codec errors. */
+ { PJMEDIA_CODEC_EUNSUP, "Unsupported media codec" },
+
+ /* Media errors. */
+ { PJMEDIA_EINVALIDIP, "Invalid remote media (IP) address" },
+ { PJMEDIA_EASYMCODEC, "Asymetric media codec is not supported" },
+ { PJMEDIA_EINVALIDPT, "Invalid media payload type" },
+ { PJMEDIA_EMISSINGRTPMAP, "Missing rtpmap in media description" },
};
diff --git a/pjmedia/src/pjmedia/g711.c b/pjmedia/src/pjmedia/g711.c
index 9d79bccf..5844208f 100644
--- a/pjmedia/src/pjmedia/g711.c
+++ b/pjmedia/src/pjmedia/g711.c
@@ -20,6 +20,7 @@
* notice in the second half of this file.
*/
#include <pjmedia/codec.h>
+#include <pjmedia/errno.h>
#include <pj/pool.h>
#include <pj/string.h>
#include <pj/assert.h>
@@ -29,8 +30,8 @@
#define G711_CODEC_CNT 0 /* number of codec to preallocate in memory */
/* These are the only public functions exported to applications */
-PJ_DECL(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool);
-PJ_DECL(pj_status_t) g711_deinit_factory (pj_codec_factory *factory);
+PJ_DECL(pj_status_t) g711_init_factory (pjmedia_codec_factory *factory, pj_pool_t *pool);
+PJ_DECL(pj_status_t) g711_deinit_factory (pjmedia_codec_factory *factory);
/* Algorithm prototypes. */
static unsigned char linear2alaw(int pcm_val); /* 2's complement (16-bit range) */
@@ -39,24 +40,24 @@ static unsigned char linear2ulaw(int pcm_val);
static int ulaw2linear(unsigned char u_val);
/* Prototypes for G711 factory */
-static pj_status_t g711_match_id( pj_codec_factory *factory, const pj_codec_id *id );
-static pj_status_t g711_default_attr( pj_codec_factory *factory, const pj_codec_id *id, pj_codec_attr *attr );
-static unsigned g711_enum_codecs (pj_codec_factory *factory, unsigned count, pj_codec_id codecs[]);
-static pj_codec* g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id *id);
-static void g711_dealloc_codec( pj_codec_factory *factory, pj_codec *codec );
+static pj_status_t g711_match_id( pjmedia_codec_factory *factory, const pjmedia_codec_info *id );
+static pj_status_t g711_default_attr( pjmedia_codec_factory *factory, const pjmedia_codec_info *id, pjmedia_codec_param *attr );
+static pj_status_t g711_enum_codecs (pjmedia_codec_factory *factory, unsigned *count, pjmedia_codec_info codecs[]);
+static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory, const pjmedia_codec_info *id, pjmedia_codec **p_codec);
+static pj_status_t g711_dealloc_codec( pjmedia_codec_factory *factory, pjmedia_codec *codec );
/* Prototypes for G711 implementation. */
-static pj_status_t g711_codec_default_attr (pj_codec *codec, pj_codec_attr *attr);
-static pj_status_t g711_init( pj_codec *codec, pj_pool_t *pool );
-static pj_status_t g711_open( pj_codec *codec, pj_codec_attr *attr );
-static pj_status_t g711_close( pj_codec *codec );
-static pj_status_t g711_encode( pj_codec *codec, const struct pj_audio_frame *input,
- unsigned output_buf_len, struct pj_audio_frame *output);
-static pj_status_t g711_decode( pj_codec *codec, const struct pj_audio_frame *input,
- unsigned output_buf_len, struct pj_audio_frame *output);
+static pj_status_t g711_codec_default_attr (pjmedia_codec *codec, pjmedia_codec_param *attr);
+static pj_status_t g711_init( pjmedia_codec *codec, pj_pool_t *pool );
+static pj_status_t g711_open( pjmedia_codec *codec, pjmedia_codec_param *attr );
+static pj_status_t g711_close( pjmedia_codec *codec );
+static pj_status_t g711_encode( pjmedia_codec *codec, const struct pjmedia_frame *input,
+ unsigned output_buf_len, struct pjmedia_frame *output);
+static pj_status_t g711_decode( pjmedia_codec *codec, const struct pjmedia_frame *input,
+ unsigned output_buf_len, struct pjmedia_frame *output);
/* Definition for G711 codec operations. */
-static pj_codec_op g711_op =
+static pjmedia_codec_op g711_op =
{
&g711_codec_default_attr ,
&g711_init,
@@ -67,7 +68,7 @@ static pj_codec_op g711_op =
};
/* Definition for G711 codec factory operations. */
-static pj_codec_factory_op g711_factory_op =
+static pjmedia_codec_factory_op g711_factory_op =
{
&g711_match_id,
&g711_default_attr,
@@ -80,7 +81,7 @@ static pj_codec_factory_op g711_factory_op =
struct g711_factory_private
{
pj_pool_t *pool;
- pj_codec codec_list;
+ pjmedia_codec codec_list;
};
/* G711 codec private data. */
@@ -90,10 +91,10 @@ struct g711_private
};
-PJ_DEF(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool)
+PJ_DEF(pj_status_t) g711_init_factory (pjmedia_codec_factory *factory, pj_pool_t *pool)
{
struct g711_factory_private *priv;
- //enum { CODEC_MEM_SIZE = sizeof(pj_codec) + sizeof(struct g711_private) + 4 };
+ //enum { CODEC_MEM_SIZE = sizeof(pjmedia_codec) + sizeof(struct g711_private) + 4 };
/* Create pool. */
/*
@@ -117,7 +118,7 @@ PJ_DEF(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *poo
return 0;
}
-PJ_DEF(pj_status_t) g711_deinit_factory (pj_codec_factory *factory)
+PJ_DEF(pj_status_t) g711_deinit_factory (pjmedia_codec_factory *factory)
{
struct g711_factory_private *priv = factory->factory_data;
@@ -127,21 +128,21 @@ PJ_DEF(pj_status_t) g711_deinit_factory (pj_codec_factory *factory)
return 0;
}
-static pj_status_t g711_match_id( pj_codec_factory *factory, const pj_codec_id *id )
+static pj_status_t g711_match_id( pjmedia_codec_factory *factory, const pjmedia_codec_info *id )
{
PJ_UNUSED_ARG(factory);
/* It's sufficient to check payload type only. */
- return (id->pt==PJ_RTP_PT_PCMU || id->pt==PJ_RTP_PT_PCMA) ? 0 : -1;
+ return (id->pt==PJMEDIA_RTP_PT_PCMU || id->pt==PJMEDIA_RTP_PT_PCMA) ? 0 : -1;
}
-static pj_status_t g711_default_attr (pj_codec_factory *factory,
- const pj_codec_id *id,
- pj_codec_attr *attr )
+static pj_status_t g711_default_attr (pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id,
+ pjmedia_codec_param *attr )
{
PJ_UNUSED_ARG(factory);
- memset(attr, 0, sizeof(pj_codec_attr));
+ memset(attr, 0, sizeof(pjmedia_codec_param));
attr->sample_rate = 8000;
attr->avg_bps = G711_BPS;
attr->pcm_bits_per_sample = 16;
@@ -153,40 +154,46 @@ static pj_status_t g711_default_attr (pj_codec_factory *factory,
return PJ_SUCCESS;
}
-static unsigned g711_enum_codecs (pj_codec_factory *factory,
- unsigned count, pj_codec_id codecs[])
+static pj_status_t g711_enum_codecs(pjmedia_codec_factory *factory,
+ unsigned *count,
+ pjmedia_codec_info codecs[])
{
PJ_UNUSED_ARG(factory);
- if (count > 0) {
- codecs[0].type = PJ_MEDIA_TYPE_AUDIO;
- codecs[0].pt = PJ_RTP_PT_PCMU;
+ if (*count > 0) {
+ codecs[0].type = PJMEDIA_TYPE_AUDIO;
+ codecs[0].pt = PJMEDIA_RTP_PT_PCMU;
codecs[0].encoding_name = pj_str("PCMU");
codecs[0].sample_rate = 8000;
}
- if (count > 1) {
- codecs[1].type = PJ_MEDIA_TYPE_AUDIO;
- codecs[1].pt = PJ_RTP_PT_PCMA;
+ if (*count > 1) {
+ codecs[1].type = PJMEDIA_TYPE_AUDIO;
+ codecs[1].pt = PJMEDIA_RTP_PT_PCMA;
codecs[1].encoding_name = pj_str("PCMA");
codecs[1].sample_rate = 8000;
}
- return 2;
+ if (*count > 0) *count=1;
+ if (*count > 1) *count=2;
+
+ return PJ_SUCCESS;
}
-static pj_codec *g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id *id)
+static pj_status_t g711_alloc_codec( pjmedia_codec_factory *factory,
+ const pjmedia_codec_info *id,
+ pjmedia_codec **p_codec)
{
struct g711_factory_private *priv = factory->factory_data;
- pj_codec *codec = NULL;
+ pjmedia_codec *codec = NULL;
/* Allocate new codec if no more is available */
if (pj_list_empty(&priv->codec_list)) {
struct g711_private *codec_priv;
- codec = pj_pool_alloc(priv->pool, sizeof(pj_codec));
+ codec = pj_pool_alloc(priv->pool, sizeof(pjmedia_codec));
codec_priv = pj_pool_alloc(priv->pool, sizeof(struct g711_private));
if (!codec || !codec_priv)
- return NULL;
+ return PJ_ENOMEM;
codec_priv->pt = id->pt;
@@ -201,33 +208,36 @@ static pj_codec *g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id
/* Zero the list, for error detection in g711_dealloc_codec */
codec->next = codec->prev = NULL;
- return codec;
+ *p_codec = codec;
+ return PJ_SUCCESS;
}
-static void g711_dealloc_codec( pj_codec_factory *factory, pj_codec *codec )
+static pj_status_t g711_dealloc_codec( pjmedia_codec_factory *factory, pjmedia_codec *codec )
{
struct g711_factory_private *priv = factory->factory_data;
/* Check that this node has not been deallocated before */
pj_assert (codec->next==NULL && codec->prev==NULL);
if (codec->next!=NULL || codec->prev!=NULL) {
- return;
+ return PJ_EINVALIDOP;
}
/* Insert at the back of the list */
pj_list_insert_before(&priv->codec_list, codec);
+
+ return PJ_SUCCESS;
}
-static pj_status_t g711_codec_default_attr (pj_codec *codec, pj_codec_attr *attr)
+static pj_status_t g711_codec_default_attr (pjmedia_codec *codec, pjmedia_codec_param *attr)
{
struct g711_private *priv = codec->codec_data;
- pj_codec_id id;
+ pjmedia_codec_info id;
id.pt = priv->pt;
return g711_default_attr (NULL, &id, attr);
}
-static pj_status_t g711_init( pj_codec *codec, pj_pool_t *pool )
+static pj_status_t g711_init( pjmedia_codec *codec, pj_pool_t *pool )
{
/* There's nothing to do here really */
PJ_UNUSED_ARG(codec);
@@ -236,22 +246,22 @@ static pj_status_t g711_init( pj_codec *codec, pj_pool_t *pool )
return PJ_SUCCESS;
}
-static pj_status_t g711_open( pj_codec *codec, pj_codec_attr *attr )
+static pj_status_t g711_open( pjmedia_codec *codec, pjmedia_codec_param *attr )
{
struct g711_private *priv = codec->codec_data;
priv->pt = attr->pt;
return PJ_SUCCESS;
}
-static pj_status_t g711_close( pj_codec *codec )
+static pj_status_t g711_close( pjmedia_codec *codec )
{
PJ_UNUSED_ARG(codec);
/* Nothing to do */
return PJ_SUCCESS;
}
-static pj_status_t g711_encode( pj_codec *codec, const struct pj_audio_frame *input,
- unsigned output_buf_len, struct pj_audio_frame *output)
+static pj_status_t g711_encode( pjmedia_codec *codec, const struct pjmedia_frame *input,
+ unsigned output_buf_len, struct pjmedia_frame *output)
{
pj_int16_t *samples = (pj_int16_t*) input->buf;
struct g711_private *priv = codec->codec_data;
@@ -261,14 +271,14 @@ static pj_status_t g711_encode( pj_codec *codec, const struct pj_audio_frame *i
return -1;
/* Encode */
- if (priv->pt == PJ_RTP_PT_PCMA) {
+ if (priv->pt == PJMEDIA_RTP_PT_PCMA) {
unsigned i;
pj_uint8_t *dst = output->buf;
for (i=0; i!=input->size/2; ++i, ++dst) {
*dst = linear2alaw(samples[i]);
}
- } else if (priv->pt == PJ_RTP_PT_PCMU) {
+ } else if (priv->pt == PJMEDIA_RTP_PT_PCMU) {
unsigned i;
pj_uint8_t *dst = output->buf;
@@ -280,14 +290,14 @@ static pj_status_t g711_encode( pj_codec *codec, const struct pj_audio_frame *i
return -1;
}
- output->type = PJ_AUDIO_FRAME_AUDIO;
+ output->type = PJMEDIA_FRAME_TYPE_AUDIO;
output->size = input->size / 2;
return 0;
}
-static pj_status_t g711_decode( pj_codec *codec, const struct pj_audio_frame *input,
- unsigned output_buf_len, struct pj_audio_frame *output)
+static pj_status_t g711_decode( pjmedia_codec *codec, const struct pjmedia_frame *input,
+ unsigned output_buf_len, struct pjmedia_frame *output)
{
struct g711_private *priv = codec->codec_data;
@@ -296,7 +306,7 @@ static pj_status_t g711_decode( pj_codec *codec, const struct pj_audio_frame *i
return -1;
/* Decode */
- if (priv->pt == PJ_RTP_PT_PCMA) {
+ if (priv->pt == PJMEDIA_RTP_PT_PCMA) {
unsigned i;
pj_uint8_t *src = input->buf;
pj_uint16_t *dst = output->buf;
@@ -304,7 +314,7 @@ static pj_status_t g711_decode( pj_codec *codec, const struct pj_audio_frame *i
for (i=0; i!=input->size; ++i) {
*dst++ = (pj_uint16_t) alaw2linear(*src++);
}
- } else if (priv->pt == PJ_RTP_PT_PCMU) {
+ } else if (priv->pt == PJMEDIA_RTP_PT_PCMU) {
unsigned i;
pj_uint8_t *src = input->buf;
pj_uint16_t *dst = output->buf;
@@ -317,7 +327,7 @@ static pj_status_t g711_decode( pj_codec *codec, const struct pj_audio_frame *i
return -1;
}
- output->type = PJ_AUDIO_FRAME_AUDIO;
+ output->type = PJMEDIA_FRAME_TYPE_AUDIO;
output->size = input->size * 2;
return 0;
diff --git a/pjmedia/src/pjmedia/mediamgr.c b/pjmedia/src/pjmedia/mediamgr.c
deleted file mode 100644
index e43e742d..00000000
--- a/pjmedia/src/pjmedia/mediamgr.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <pjmedia/mediamgr.h>
-#include <pj/sock.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-
-PJ_DECL(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool);
-PJ_DECL(pj_status_t) g711_deinit_factory (pj_codec_factory *factory);
-
-/** Concrete declaration of media manager. */
-struct pj_med_mgr_t
-{
- /** Pool. */
- pj_pool_t *pool;
-
- /** Pool factory. */
- pj_pool_factory *pf;
-
- /** Codec manager. */
- pj_codec_mgr codec_mgr;
-};
-
-/**
- * Initialize and get the instance of media manager.
- */
-PJ_DEF(pj_med_mgr_t*) pj_med_mgr_create ( pj_pool_factory *pf)
-{
- pj_pool_t *pool;
- pj_med_mgr_t *mm;
- pj_codec_factory *cf;
- pj_status_t status;
-
- pool = pj_pool_create(pf, "mediamgr", 512, 512, NULL);
- if (!pool)
- return NULL;
-
- mm = pj_pool_calloc(pool, 1, sizeof(struct pj_med_mgr_t));
- mm->pool = pool;
- mm->pf = pf;
-
- /* Sound */
- pj_snd_init(pf);
-
- /* Init codec manager. */
- status = pj_codec_mgr_init(&mm->codec_mgr);
- if (status != 0) {
- pj_snd_deinit();
- goto on_error;
- }
-
- /* Init and register G.711 codec. */
- cf = pj_pool_alloc (mm->pool, sizeof(pj_codec_factory));
-
- status = g711_init_factory (cf, mm->pool);
- if (status != 0) {
- pj_snd_deinit();
- return NULL;
- }
-
- status = pj_codec_mgr_register_factory (&mm->codec_mgr, cf);
- if (status != 0)
- return NULL;
-
- return mm;
-
-on_error:
- pj_pool_release(pool);
- return NULL;
-}
-
-/**
- * Get the codec manager instance.
- */
-PJ_DEF(pj_codec_mgr*) pj_med_mgr_get_codec_mgr (pj_med_mgr_t *mgr)
-{
- return &mgr->codec_mgr;
-}
-
-/**
- * Deinitialize media manager.
- */
-PJ_DEF(pj_status_t) pj_med_mgr_destroy (pj_med_mgr_t *mgr)
-{
- pj_snd_deinit();
- pj_pool_release (mgr->pool);
- return 0;
-}
-
-/**
- * Get pool factory.
- */
-PJ_DEF(pj_pool_factory*) pj_med_mgr_get_pool_factory (pj_med_mgr_t *mgr)
-{
- return mgr->pf;
-}
diff --git a/pjmedia/src/pjmedia/rtcp.c b/pjmedia/src/pjmedia/rtcp.c
index 5f45775a..14cc065b 100644
--- a/pjmedia/src/pjmedia/rtcp.c
+++ b/pjmedia/src/pjmedia/rtcp.c
@@ -92,7 +92,7 @@ PJ_DEF(void) pj_rtcp_rx_rtp(pj_rtcp_session *s, pj_uint16_t seq, pj_uint32_t rtp
/* Update sequence numbers (received, lost, etc). */
status = pj_rtp_seq_update(&s->seq_ctrl, seq);
- if (status == PJ_RTP_ERR_SESSION_RESTARTED) {
+ if (status == PJMEDIA_RTP_ERR_SESSION_RESTARTED) {
rtcp_init_seq(s, seq);
status = 0;
}
diff --git a/pjmedia/src/pjmedia/rtp.c b/pjmedia/src/pjmedia/rtp.c
index 5a337937..8d653698 100644
--- a/pjmedia/src/pjmedia/rtp.c
+++ b/pjmedia/src/pjmedia/rtp.c
@@ -43,7 +43,7 @@ PJ_DEF(pj_status_t) pj_rtp_session_init( pj_rtp_session *ses,
/* Check RTP header packing. */
if (sizeof(struct pj_rtp_hdr) != 12) {
pj_assert(!"Wrong RTP header packing!");
- return PJ_RTP_ERR_RTP_PACKING;
+ return PJMEDIA_RTP_ERR_RTP_PACKING;
}
/* If sender_ssrc is not specified, create from time value. */
@@ -128,7 +128,7 @@ PJ_DEF(pj_status_t) pj_rtp_decode_rtp( pj_rtp_session *ses,
/* Check RTP header sanity. */
if ((*hdr)->v != RTP_VERSION) {
PJ_LOG(4, (THIS_FILE, " invalid RTP version!"));
- return PJ_RTP_ERR_INVALID_VERSION;
+ return PJMEDIA_RTP_ERR_INVALID_VERSION;
}
/* Payload is located right after header plus CSRC */
@@ -142,7 +142,7 @@ PJ_DEF(pj_status_t) pj_rtp_decode_rtp( pj_rtp_session *ses,
/* Check that offset is less than packet size */
if (offset >= pkt_len)
- return PJ_RTP_ERR_INVALID_PACKET;
+ return PJMEDIA_RTP_ERR_INVALID_PACKET;
/* Find and set payload. */
*payload = ((pj_uint8_t*)pkt) + offset;
@@ -162,7 +162,7 @@ PJ_DEF(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, const pj_rtp_hdr
if (pj_ntohl(ses->peer_ssrc) != hdr->ssrc) {
PJ_LOG(4, (THIS_FILE, "pj_rtp_session_update: ses=%p, invalid ssrc 0x%p (!=0x%p)",
ses, pj_ntohl(hdr->ssrc), ses->peer_ssrc));
- return PJ_RTP_ERR_INVALID_SSRC;
+ return PJMEDIA_RTP_ERR_INVALID_SSRC;
}
*/
@@ -170,7 +170,7 @@ PJ_DEF(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, const pj_rtp_hdr
if (hdr->pt != ses->out_pt) {
PJ_LOG(4, (THIS_FILE, "pj_rtp_session_update: ses=%p, invalid payload type %d (!=%d)",
ses, hdr->pt, ses->out_pt));
- return PJ_RTP_ERR_INVALID_PT;
+ return PJMEDIA_RTP_ERR_INVALID_PT;
}
/* Initialize sequence number on first packet received. */
@@ -179,10 +179,10 @@ PJ_DEF(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, const pj_rtp_hdr
/* Check sequence number to see if remote session has been restarted. */
status = pj_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq));
- if (status == PJ_RTP_ERR_SESSION_RESTARTED) {
+ if (status == PJMEDIA_RTP_ERR_SESSION_RESTARTED) {
pj_rtp_seq_restart( &ses->seq_ctrl, pj_ntohs(hdr->seq));
++ses->received;
- } else if (status == 0 || status == PJ_RTP_ERR_SESSION_PROBATION) {
+ } else if (status == 0 || status == PJMEDIA_RTP_ERR_SESSION_PROBATION) {
++ses->received;
}
@@ -223,13 +223,13 @@ int pj_rtp_seq_update(pj_rtp_seq_session *sctrl, pj_uint16_t seq)
sctrl->probation--;
sctrl->max_seq = seq;
if (sctrl->probation == 0) {
- return PJ_RTP_ERR_SESSION_RESTARTED;
+ return PJMEDIA_RTP_ERR_SESSION_RESTARTED;
}
} else {
sctrl->probation = MIN_SEQUENTIAL - 1;
sctrl->max_seq = seq;
}
- return PJ_RTP_ERR_SESSION_PROBATION;
+ return PJMEDIA_RTP_ERR_SESSION_PROBATION;
} else if (udelta < MAX_DROPOUT) {
/* in order, with permissible gap */
@@ -247,11 +247,11 @@ int pj_rtp_seq_update(pj_rtp_seq_session *sctrl, pj_uint16_t seq)
* restarted without telling us so just re-sync
* (i.e., pretend this was the first packet).
*/
- return PJ_RTP_ERR_SESSION_RESTARTED;
+ return PJMEDIA_RTP_ERR_SESSION_RESTARTED;
}
else {
sctrl->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
- return PJ_RTP_ERR_BAD_SEQUENCE;
+ return PJMEDIA_RTP_ERR_BAD_SEQUENCE;
}
} else {
/* duplicate or reordered packet */
diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c
index 996ed474..1ddb13b4 100644
--- a/pjmedia/src/pjmedia/session.c
+++ b/pjmedia/src/pjmedia/session.c
@@ -17,31 +17,28 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjmedia/session.h>
+#include <pjmedia/errno.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/pool.h>
#include <pj/string.h>
#include <pj/assert.h>
+#include <pj/ctype.h>
-typedef struct pj_media_stream_desc
-{
- pj_media_stream_info info;
- pj_media_stream_t *enc_stream, *dec_stream;
-} pj_media_stream_desc;
-
-struct pj_media_session_t
+struct pjmedia_session
{
pj_pool_t *pool;
- pj_med_mgr_t *mediamgr;
+ pjmedia_endpt *endpt;
unsigned stream_cnt;
- pj_media_stream_desc *stream_desc[PJSDP_MAX_MEDIA];
+ pjmedia_stream_info stream_info[PJSDP_MAX_MEDIA];
+ pjmedia_stream *stream[PJSDP_MAX_MEDIA];
};
#define THIS_FILE "session.c"
-#define PJ_MEDIA_SESSION_SIZE (48*1024)
-#define PJ_MEDIA_SESSION_INC 1024
+#define PJMEDIA_SESSION_SIZE (48*1024)
+#define PJMEDIA_SESSION_INC 1024
static const pj_str_t ID_AUDIO = { "audio", 5};
static const pj_str_t ID_VIDEO = { "video", 5};
@@ -49,787 +46,350 @@ static const pj_str_t ID_IN = { "IN", 2 };
static const pj_str_t ID_IP4 = { "IP4", 3};
static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };
static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 };
+static const pj_str_t ID_RTPMAP = { "rtpmap", 6 };
-static void session_init (pj_media_session_t *ses)
-{
- pj_memset (ses, 0, sizeof(pj_media_session_t));
-}
+static const pj_str_t STR_INACTIVE = { "inactive", 8 };
+static const pj_str_t STR_SENDRECV = { "sendrecv", 8 };
+static const pj_str_t STR_SENDONLY = { "sendonly", 8 };
+static const pj_str_t STR_RECVONLY = { "recvonly", 8 };
-/**
- * Create new session offering.
+/*
+ * Create stream info from SDP media line.
*/
-PJ_DEF(pj_media_session_t*)
-pj_media_session_create (pj_med_mgr_t *mgr, const pj_media_sock_info *sock_info)
+static pj_status_t create_stream_info_from_sdp(pj_pool_t *pool,
+ pjmedia_stream_info *si,
+ const pjmedia_sdp_conn *local_conn,
+ const pjmedia_sdp_conn *rem_conn,
+ const pjmedia_sdp_media *local_m,
+ const pjmedia_sdp_media *rem_m)
{
- pj_pool_factory *pf;
- pj_pool_t *pool;
- pj_media_session_t *session;
- pj_media_stream_desc *sd;
- unsigned i, codec_cnt;
- pj_codec_mgr *cm;
- const pj_codec_id *codecs[PJSDP_MAX_FMT];
-
- pf = pj_med_mgr_get_pool_factory(mgr);
+ const pjmedia_sdp_attr *attr;
+ pjmedia_sdp_rtpmap *rtpmap;
+ pj_status_t status;
- pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);
- if (!pool)
- return NULL;
- session = pj_pool_alloc(pool, sizeof(pj_media_session_t));
- if (!session)
- return NULL;
+ /* Validate arguments: */
- session_init (session);
+ PJ_ASSERT_RETURN(pool && si && local_conn && rem_conn &&
+ local_m && rem_m, PJ_EINVAL);
- session->pool = pool;
- session->mediamgr = mgr;
-
- /* Create first stream */
- sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc));
- if (!sd)
- return NULL;
-
- sd->info.type = ID_AUDIO;
- sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;
- sd->info.transport = ID_RTP_AVP;
- pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info));
-
- /* Enum audio codecs. */
- sd->info.fmt_cnt = 0;
- cm = pj_med_mgr_get_codec_mgr (mgr);
- codec_cnt = pj_codec_mgr_enum_codecs(cm, PJSDP_MAX_FMT, codecs);
- if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT;
- for (i=0; i<codec_cnt; ++i) {
- if (codecs[i]->type != PJ_MEDIA_TYPE_AUDIO)
- continue;
-
- sd->info.fmt[sd->info.fmt_cnt].pt = codecs[i]->pt;
- sd->info.fmt[sd->info.fmt_cnt].sample_rate = codecs[i]->sample_rate;
- pj_strdup (pool, &sd->info.fmt[sd->info.fmt_cnt].encoding_name, &codecs[i]->encoding_name);
- ++sd->info.fmt_cnt;
- }
+ /* Reset: */
- session->stream_desc[session->stream_cnt++] = sd;
+ pj_memset(si, 0, sizeof(*si));
- return session;
-}
+ /* Media type: */
-static int sdp_check (const pjsdp_session_desc *sdp)
-{
- int has_conn = 0;
- unsigned i;
+ if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) == 0) {
- if (sdp->conn)
- has_conn = 1;
+ si->type = PJMEDIA_TYPE_AUDIO;
- if (sdp->media_count == 0) {
- PJ_LOG(4,(THIS_FILE, "SDP check failed: no media stream definition"));
- return -1;
- }
+ } else if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) == 0) {
- for (i=0; i<sdp->media_count; ++i) {
- pjsdp_media_desc *m = sdp->media[i];
+ si->type = PJMEDIA_TYPE_VIDEO;
- if (!m) {
- pj_assert(0);
- return -1;
- }
+ } else {
- if (m->desc.fmt_count == 0) {
- PJ_LOG(4,(THIS_FILE, "SDP check failed: no format listed in media stream"));
- return -1;
- }
+ si->type = PJMEDIA_TYPE_UNKNOWN;
- if (!has_conn && m->conn == NULL) {
- PJ_LOG(4,(THIS_FILE, "SDP check failed: no connection information for media"));
- return -1;
- }
}
- return 0;
-}
-
-/*
- * Create local stream definition that matches SDP received from peer.
- */
-static pj_media_stream_desc*
-create_stream_from_sdp (pj_pool_t *pool, pj_med_mgr_t *mgr, const pjsdp_conn_info *conn,
- const pjsdp_media_desc *m, const pj_media_sock_info *sock_info)
-{
- pj_media_stream_desc *sd;
-
- sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc));
- if (!sd) {
- PJ_LOG(2,(THIS_FILE, "No memory to allocate stream descriptor"));
- return NULL;
- }
+ /* Media direction: */
- if (pj_stricmp(&conn->net_type, &ID_IN)==0 &&
- pj_stricmp(&conn->addr_type, &ID_IP4)==0 &&
- pj_stricmp(&m->desc.media, &ID_AUDIO)==0 &&
- pj_stricmp(&m->desc.transport, &ID_RTP_AVP) == 0)
+ if (local_m->desc.port == 0 ||
+ pj_inet_addr(&local_conn->addr).s_addr==0 ||
+ pj_inet_addr(&rem_conn->addr).s_addr==0 ||
+ pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)
{
- /*
- * Got audio stream.
- */
- unsigned i, codec_cnt;
- pj_codec_mgr *cm;
- const pj_codec_id *codecs[PJSDP_MAX_FMT];
-
- sd->info.type = ID_AUDIO;
- sd->info.transport = ID_RTP_AVP;
- pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info));
- sd->info.rem_port = m->desc.port;
- pj_strdup (pool, &sd->info.rem_addr, &conn->addr);
-
- /* Enum audio codecs. */
- sd->info.fmt_cnt = 0;
- cm = pj_med_mgr_get_codec_mgr (mgr);
- codec_cnt = pj_codec_mgr_enum_codecs (cm, PJSDP_MAX_FMT, codecs);
- if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT;
-
- /* Find just one codec which we can support. */
- for (i=0; i<m->desc.fmt_count && sd->info.fmt_cnt == 0; ++i) {
- unsigned j, fmt_i;
-
- /* For static payload, just match payload type. */
- /* Else match clock rate and encoding name. */
- fmt_i = pj_strtoul(&m->desc.fmt[i]);
- if (fmt_i < PJ_RTP_PT_DYNAMIC) {
- for (j=0; j<codec_cnt; ++j) {
- if (codecs[j]->pt == fmt_i) {
- sd->info.fmt_cnt = 1;
- sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO;
- sd->info.fmt[0].pt = codecs[j]->pt;
- sd->info.fmt[0].sample_rate = codecs[j]->sample_rate;
- pj_strdup (pool, &sd->info.fmt[0].encoding_name, &codecs[j]->encoding_name);
- break;
- }
- }
- } else {
-
- /* Find the rtpmap for the payload type. */
- const pjsdp_rtpmap_attr *rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_i);
-
- /* Don't accept the media if no rtpmap for dynamic PT. */
- if (rtpmap == NULL) {
- PJ_LOG(4,(THIS_FILE, "SDP: No rtpmap found for payload id %d", m->desc.fmt[i]));
- continue;
- }
-
- /* Check whether we can take this codec. */
- for (j=0; j<codec_cnt; ++j) {
- if (rtpmap->clock_rate == codecs[j]->sample_rate &&
- pj_stricmp(&rtpmap->encoding_name, &codecs[j]->encoding_name) == 0)
- {
- sd->info.fmt_cnt = 1;
- sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO;
- sd->info.fmt[0].pt = codecs[j]->pt;
- sd->info.fmt[0].sample_rate = codecs[j]->sample_rate;
- sd->info.fmt[0].encoding_name = codecs[j]->encoding_name;
- break;
- }
- }
- }
- }
+ /* Inactive stream. */
- /* Match codec and direction. */
- if (sd->info.fmt_cnt == 0 || m->desc.port == 0 ||
- pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE))
- {
- sd->info.dir = PJ_MEDIA_DIR_NONE;
- }
- else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) {
- sd->info.dir = PJ_MEDIA_DIR_ENCODING;
- }
- else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) {
- sd->info.dir = PJ_MEDIA_DIR_DECODING;
- }
- else {
- sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;
- }
+ si->dir = PJMEDIA_DIR_NONE;
- } else {
- /* Unsupported media stream. */
- unsigned fmt_num;
- const pjsdp_rtpmap_attr *rtpmap = NULL;
-
- pj_strdup(pool, &sd->info.type, &m->desc.media);
- pj_strdup(pool, &sd->info.transport, &m->desc.transport);
- pj_memset(&sd->info.sock_info, 0, sizeof(*sock_info));
- pj_strdup (pool, &sd->info.rem_addr, &conn->addr);
- sd->info.rem_port = m->desc.port;
-
- /* Just put one format and rtpmap, so that we don't have to make
- * special exception when we convert this stream to SDP.
- */
-
- /* Find the rtpmap for the payload type. */
- fmt_num = pj_strtoul(&m->desc.fmt[0]);
- rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_num);
-
- sd->info.fmt_cnt = 1;
- if (pj_stricmp(&m->desc.media, &ID_VIDEO)==0) {
- sd->info.fmt[0].type = PJ_MEDIA_TYPE_VIDEO;
- sd->info.fmt[0].pt = fmt_num;
- if (rtpmap) {
- pj_strdup (pool, &sd->info.fmt[0].encoding_name,
- &rtpmap->encoding_name);
- sd->info.fmt[0].sample_rate = rtpmap->clock_rate;
- }
- } else {
- sd->info.fmt[0].type = PJ_MEDIA_TYPE_UNKNOWN;
- pj_strdup(pool, &sd->info.fmt[0].encoding_name, &m->desc.fmt[0]);
- }
-
- sd->info.dir = PJ_MEDIA_DIR_NONE;
- }
+ } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {
- return sd;
-}
+ /* Send only stream. */
-/**
- * Create new session based on peer's offering.
- */
-PJ_DEF(pj_media_session_t*)
-pj_media_session_create_from_sdp (pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp,
- const pj_media_sock_info *sock_info)
-{
- pj_pool_factory *pf;
- pj_pool_t *pool;
- pj_media_session_t *session;
- unsigned i;
+ si->dir = PJMEDIA_DIR_ENCODING;
- if (sdp_check(sdp) != 0)
- return NULL;
+ } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {
- pf = pj_med_mgr_get_pool_factory(mgr);
- pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);
- if (!pool)
- return NULL;
+ /* Recv only stream. */
- session = pj_pool_alloc(pool, sizeof(pj_media_session_t));
- if (!session) {
- PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor"));
- pj_pool_release (pool);
- return NULL;
- }
+ si->dir = PJMEDIA_DIR_DECODING;
+
+ } else {
- session_init (session);
+ /* Send and receive stream. */
- session->pool = pool;
- session->mediamgr = mgr;
+ si->dir = PJMEDIA_DIR_ENCODING_DECODING;
- /* Enumerate each media stream and create our peer. */
- for (i=0; i<sdp->media_count; ++i) {
- const pjsdp_conn_info *conn;
- const pjsdp_media_desc *m;
- pj_media_stream_desc *sd;
+ }
- m = sdp->media[i];
- conn = m->conn ? m->conn : sdp->conn;
- /*
- * Bug:
- * the sock_info below is used by more than one 'm' lines
- */
- PJ_TODO(SUPPORT_MORE_THAN_ONE_SDP_M_LINES)
+ /* Set remote address: */
- sd = create_stream_from_sdp (pool, mgr, conn, m, sock_info);
- pj_assert (sd);
+ si->rem_addr.sin_family = PJ_AF_INET;
+ si->rem_addr.sin_port = pj_htons(rem_m->desc.port);
+ if (pj_inet_aton(&rem_conn->addr, &si->rem_addr.sin_addr) == 0) {
- session->stream_desc[session->stream_cnt++] = sd;
+ /* Invalid IP address. */
+ return PJMEDIA_EINVALIDIP;
}
- return session;
-}
+ /* For this version of PJMEDIA, send and receive media must use
+ * the same codec.
+ */
+ if (pj_strcmp(&local_m->desc.fmt[0], &rem_m->desc.fmt[0]) != 0)
+ return PJMEDIA_EASYMCODEC;
-/**
- * Duplicate session. The new session is inactive.
- */
-PJ_DEF(pj_media_session_t*)
-pj_media_session_clone (const pj_media_session_t *rhs)
-{
- pj_pool_factory *pf;
- pj_pool_t *pool;
- pj_media_session_t *session;
- unsigned i;
- pf = pj_med_mgr_get_pool_factory(rhs->mediamgr);
- pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);
- if (!pool) {
- return NULL;
- }
+ /* And codec must be numeric! */
+ if (!pj_isdigit(*local_m->desc.fmt[0].ptr))
+ return PJMEDIA_EINVALIDPT;
- session = pj_pool_alloc (pool, sizeof(*session));
- if (!session) {
- PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor"));
- pj_pool_release (pool);
- return NULL;
- }
+ /* Find rtpmap for the first codec.
+ * For this version of PJMEDIA, we do not support static payload
+ * type without rtpmap.
+ */
+ attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, NULL);
+ if (attr == NULL)
+ return PJMEDIA_EMISSINGRTPMAP;
- session->pool = pool;
- session->mediamgr = rhs->mediamgr;
- session->stream_cnt = rhs->stream_cnt;
+ status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
+ if (status != PJ_SUCCESS)
+ return status;
- for (i=0; i<rhs->stream_cnt; ++i) {
- pj_media_stream_desc *sd1 = pj_pool_alloc (session->pool, sizeof(pj_media_stream_desc));
- const pj_media_stream_desc *sd2 = rhs->stream_desc[i];
+ /* Build codec format info: */
- if (!sd1) {
- PJ_LOG(3,(THIS_FILE, "No memory to create media stream descriptor"));
- pj_pool_release (pool);
- return NULL;
- }
+ si->fmt.type = si->type;
+ si->fmt.pt = pj_strtoul(&local_m->desc.fmt[0]);
+ pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);
+ si->fmt.sample_rate = rtpmap->clock_rate;
- session->stream_desc[i] = sd1;
- sd1->enc_stream = sd1->dec_stream = NULL;
- pj_strdup (pool, &sd1->info.type, &sd2->info.type);
- sd1->info.dir = sd2->info.dir;
- pj_strdup (pool, &sd1->info.transport, &sd2->info.transport);
- pj_memcpy(&sd1->info.sock_info, &sd2->info.sock_info, sizeof(pj_media_sock_info));
- pj_strdup (pool, &sd1->info.rem_addr, &sd2->info.rem_addr);
- sd1->info.rem_port = sd2->info.rem_port;
- sd1->info.fmt_cnt = sd2->info.fmt_cnt;
- pj_memcpy (sd1->info.fmt, sd2->info.fmt, sizeof(sd2->info.fmt));
- }
+ /* Leave SSRC to zero. */
- return session;
+ /* Leave jitter buffer parameter. */
+
+ return PJ_SUCCESS;
}
+
/**
- * Create SDP description from the session.
+ * Create new session.
*/
-PJ_DEF(pjsdp_session_desc*)
-pj_media_session_create_sdp (const pj_media_session_t *session, pj_pool_t *pool,
- pj_bool_t only_first_fmt)
+PJ_DEF(pj_status_t) pjmedia_session_create( pjmedia_endpt *endpt,
+ unsigned stream_cnt,
+ const pjmedia_sock_info skinfo[],
+ const pjmedia_sdp_session *local_sdp,
+ const pjmedia_sdp_session *rem_sdp,
+ pjmedia_session **p_session )
{
- pjsdp_session_desc *sdp;
- pj_time_val tv;
- unsigned i;
- pj_media_sock_info *c_addr = NULL;
+ pj_pool_t *pool;
+ pjmedia_session *session;
+ int i; /* Must be signed */
+ pj_status_t status;
- if (session->stream_cnt == 0) {
- pj_assert(0);
- return NULL;
- }
+ /* Verify arguments. */
+ PJ_ASSERT_RETURN(endpt && stream_cnt && skinfo &&
+ local_sdp && rem_sdp && p_session, PJ_EINVAL);
- sdp = pj_pool_calloc (pool, 1, sizeof(pjsdp_session_desc));
- if (!sdp) {
- PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP session descriptor"));
- return NULL;
- }
+ /* Create pool for the session. */
+ pool = pjmedia_endpt_create_pool( endpt, "session",
+ PJMEDIA_SESSION_SIZE,
+ PJMEDIA_SESSION_INC);
+ PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
- pj_gettimeofday(&tv);
+ session = pj_pool_zalloc(pool, sizeof(pjmedia_session));
+ session->pool = pool;
+ session->endpt = endpt;
+ session->stream_cnt = stream_cnt;
+
+ /* Stream count is the lower number of stream_cnt or SDP m= lines count */
+ if (stream_cnt < local_sdp->media_count)
+ stream_cnt = local_sdp->media_count;
- sdp->origin.user = pj_str("-");
- sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
- sdp->origin.net_type = ID_IN;
- sdp->origin.addr_type = ID_IP4;
- sdp->origin.addr = *pj_gethostname();
+ /*
+ * Create streams:
+ */
+ for (i=0; i<(int)stream_cnt; ++i) {
- sdp->name = ID_SDP_NAME;
+ pjmedia_stream_info *si = &session->stream_info[i];
+ const pjmedia_sdp_media *local_m = local_sdp->media[i];
+ const pjmedia_sdp_media *rem_m = rem_sdp->media[i];
+ pjmedia_sdp_conn *local_conn, *rem_conn;
- /* If all media addresses are the same, then put the connection
- * info in the session level, otherwise put it in media stream
- * level.
- */
- for (i=0; i<session->stream_cnt; ++i) {
- if (c_addr == NULL) {
- c_addr = &session->stream_desc[i]->info.sock_info;
- } else if (c_addr->rtp_addr_name.sin_addr.s_addr != session->stream_desc[i]->info.sock_info.rtp_addr_name.sin_addr.s_addr)
- {
- c_addr = NULL;
- break;
- }
- }
+ /* Build stream info based on media line in local SDP */
+ local_conn = local_m->conn ? local_m->conn : local_sdp->conn;
+ rem_conn = rem_m->conn ? rem_m->conn : rem_sdp->conn;
- if (c_addr) {
- /* All addresses are the same, put connection info in session level. */
- sdp->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));
- if (!sdp->conn) {
- PJ_LOG(2,(THIS_FILE, "No memory to allocate SDP connection info"));
- return NULL;
- }
+ status = create_stream_info_from_sdp(session->pool, si,
+ local_conn, rem_conn,
+ local_m, rem_m);
+ if (status != PJ_SUCCESS)
+ return status;
- sdp->conn->net_type = ID_IN;
- sdp->conn->addr_type = ID_IP4;
- pj_strdup2 (pool, &sdp->conn->addr, pj_inet_ntoa(c_addr->rtp_addr_name.sin_addr));
+ /* Assign sockinfo */
+ si->sock_info = skinfo[i];
}
- sdp->time.start = sdp->time.stop = 0;
- sdp->attr_count = 0;
-
- /* Create each media. */
- sdp->media_count = 0;
- for (i=0; i<session->stream_cnt; ++i) {
- const pj_media_stream_desc *sd = session->stream_desc[i];
- pjsdp_media_desc *m;
- unsigned j;
- unsigned fmt_cnt;
- pjsdp_attr *attr;
-
- m = pj_pool_calloc (pool, 1, sizeof(pjsdp_media_desc));
- if (!m) {
- PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media stream descriptor"));
- return NULL;
- }
+ /*
+ * Now create the stream!
+ */
+ for (i=0; i<(int)stream_cnt; ++i) {
- sdp->media[sdp->media_count++] = m;
-
- pj_strdup (pool, &m->desc.media, &sd->info.type);
- m->desc.port = pj_ntohs(sd->info.sock_info.rtp_addr_name.sin_port);
- m->desc.port_count = 1;
- pj_strdup (pool, &m->desc.transport, &sd->info.transport);
-
- /* Add format and rtpmap for each codec. */
- m->desc.fmt_count = 0;
- m->attr_count = 0;
- fmt_cnt = sd->info.fmt_cnt;
- if (fmt_cnt > 0 && only_first_fmt)
- fmt_cnt = 1;
- for (j=0; j<fmt_cnt; ++j) {
- pjsdp_rtpmap_attr *rtpmap;
- pj_str_t *fmt = &m->desc.fmt[m->desc.fmt_count++];
-
- if (sd->info.fmt[j].type==PJ_MEDIA_TYPE_UNKNOWN) {
- pj_strdup(pool, fmt, &sd->info.fmt[j].encoding_name);
- } else {
- fmt->ptr = pj_pool_alloc(pool, 8);
- fmt->slen = pj_utoa(sd->info.fmt[j].pt, fmt->ptr);
-
- rtpmap = pj_pool_calloc(pool, 1, sizeof(pjsdp_rtpmap_attr));
- if (rtpmap) {
- m->attr[m->attr_count++] = (pjsdp_attr*)rtpmap;
- rtpmap->type = PJSDP_ATTR_RTPMAP;
- rtpmap->payload_type = sd->info.fmt[j].pt;
- rtpmap->clock_rate = sd->info.fmt[j].sample_rate;
- pj_strdup (pool, &rtpmap->encoding_name, &sd->info.fmt[j].encoding_name);
- } else {
- PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP rtpmap descriptor"));
- }
- }
- }
+ status = pjmedia_stream_create(endpt, session->pool,
+ &session->stream_info[i],
+ &session->stream[i]);
+ if (status != PJ_SUCCESS) {
- /* If we don't have connection info in session level, create one. */
- if (sdp->conn == NULL) {
- m->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));
- if (m->conn) {
- m->conn->net_type = ID_IN;
- m->conn->addr_type = ID_IP4;
- pj_strdup2 (pool, &m->conn->addr, pj_inet_ntoa(sd->info.sock_info.rtp_addr_name.sin_addr));
- } else {
- PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media connection info"));
- return NULL;
+ for ( --i; i>=0; ++i) {
+ pjmedia_stream_destroy(session->stream[i]);
}
- }
- /* Add additional attribute to the media stream. */
- attr = pj_pool_alloc(pool, sizeof(pjsdp_attr));
- if (!attr) {
- PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP attribute"));
- return NULL;
- }
- m->attr[m->attr_count++] = attr;
-
- switch (sd->info.dir) {
- case PJ_MEDIA_DIR_NONE:
- attr->type = PJSDP_ATTR_INACTIVE;
- break;
- case PJ_MEDIA_DIR_ENCODING:
- attr->type = PJSDP_ATTR_SEND_ONLY;
- break;
- case PJ_MEDIA_DIR_DECODING:
- attr->type = PJSDP_ATTR_RECV_ONLY;
- break;
- case PJ_MEDIA_DIR_ENCODING_DECODING:
- attr->type = PJSDP_ATTR_SEND_RECV;
- break;
+ pj_pool_release(session->pool);
+ return status;
}
}
- return sdp;
+
+ /* Done. */
+
+ *p_session = session;
+ return PJ_SUCCESS;
}
+
/**
- * Update session with SDP answer from peer.
+ * Destroy media session.
*/
-PJ_DEF(pj_status_t)
-pj_media_session_update (pj_media_session_t *session,
- const pjsdp_session_desc *sdp)
+PJ_DEF(pj_status_t) pjmedia_session_destroy (pjmedia_session *session)
{
unsigned i;
- unsigned count;
-
- /* Check SDP */
- if (sdp_check (sdp) != 0) {
- return -1;
- }
-
- /* If the media stream count doesn't match, only update one. */
- if (session->stream_cnt != sdp->media_count) {
- PJ_LOG(3,(THIS_FILE, "pj_media_session_update : "
- "SDP media count mismatch! (rmt=%d, lcl=%d)",
- sdp->media_count, session->stream_cnt));
- count = (session->stream_cnt < sdp->media_count) ?
- session->stream_cnt : sdp->media_count;
- } else {
- count = session->stream_cnt;
- }
-
- for (i=0; i<count; ++i) {
- pj_media_stream_desc *sd = session->stream_desc[i];
- const pjsdp_media_desc *m = sdp->media[i];
- const pjsdp_conn_info *conn;
- unsigned j;
-
- /* Check that the session is not active. */
- pj_assert (sd->enc_stream == NULL && sd->dec_stream == NULL);
-
- conn = m->conn ? m->conn : sdp->conn;
- pj_assert(conn);
-
- /* Update remote address. */
- sd->info.rem_port = m->desc.port;
- pj_strdup (session->pool, &sd->info.rem_addr, &conn->addr);
-
- /* Select one active codec according to what peer wants. */
- for (j=0; j<sd->info.fmt_cnt; ++j) {
- unsigned fmt_0 = pj_strtoul(&m->desc.fmt[0]);
- if (sd->info.fmt[j].pt == fmt_0) {
- pj_codec_id temp;
-
- /* Put active format to the front. */
- if (j == 0)
- break;
- pj_memcpy(&temp, &sd->info.fmt[0], sizeof(temp));
- pj_memcpy(&sd->info.fmt[0], &sd->info.fmt[j], sizeof(temp));
- pj_memcpy(&sd->info.fmt[j], &temp, sizeof(temp));
- break;
- }
- }
+ PJ_ASSERT_RETURN(session, PJ_EINVAL);
- if (j == sd->info.fmt_cnt) {
- /* Peer has answered SDP with new codec, which doesn't exist
- * in the offer!
- * Mute this media.
- */
- PJ_LOG(3,(THIS_FILE, "Peer has answered SDP with new codec!"));
- sd->info.dir = PJ_MEDIA_DIR_NONE;
- continue;
- }
+ for (i=0; i<session->stream_cnt; ++i) {
+
+ pjmedia_stream_destroy(session->stream[i]);
- /* Check direction. */
- if (m->desc.port == 0 || pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE)) {
- sd->info.dir = PJ_MEDIA_DIR_NONE;
- }
- else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) {
- sd->info.dir = PJ_MEDIA_DIR_ENCODING;
- }
- else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) {
- sd->info.dir = PJ_MEDIA_DIR_DECODING;
- }
- else {
- sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;
- }
}
- return 0;
+ pj_pool_release (session->pool);
+
+ return PJ_SUCCESS;
}
+
/**
- * Enumerate media streams in the session.
+ * Activate all stream in media session.
+ *
*/
-PJ_DEF(unsigned)
-pj_media_session_enum_streams (const pj_media_session_t *session,
- unsigned count, const pj_media_stream_info *info[])
+PJ_DEF(pj_status_t) pjmedia_session_resume(pjmedia_session *session,
+ pjmedia_dir dir)
{
unsigned i;
- if (count > session->stream_cnt)
- count = session->stream_cnt;
+ PJ_ASSERT_RETURN(session, PJ_EINVAL);
- for (i=0; i<count; ++i) {
- info[i] = &session->stream_desc[i]->info;
+ for (i=0; i<session->stream_cnt; ++i) {
+ pjmedia_session_resume_stream(session, i, dir);
}
- return session->stream_cnt;
+ return PJ_SUCCESS;
}
+
/**
- * Get statistics
+ * Suspend receipt and transmission of all stream in media session.
+ *
*/
-PJ_DEF(pj_status_t)
-pj_media_session_get_stat (const pj_media_session_t *session, unsigned index,
- pj_media_stream_stat *tx_stat,
- pj_media_stream_stat *rx_stat)
+PJ_DEF(pj_status_t) pjmedia_session_pause(pjmedia_session *session,
+ pjmedia_dir dir)
{
- pj_media_stream_desc *sd;
- int stat_cnt = 0;
-
- if (index >= session->stream_cnt) {
- pj_assert(0);
- return -1;
- }
-
- sd = session->stream_desc[index];
+ unsigned i;
- if (sd->enc_stream && tx_stat) {
- pj_media_stream_get_stat (sd->enc_stream, tx_stat);
- ++stat_cnt;
- } else if (tx_stat) {
- pj_memset (tx_stat, 0, sizeof(*tx_stat));
- }
+ PJ_ASSERT_RETURN(session, PJ_EINVAL);
- if (sd->dec_stream && rx_stat) {
- pj_media_stream_get_stat (sd->dec_stream, rx_stat);
- ++stat_cnt;
- } else if (rx_stat) {
- pj_memset (rx_stat, 0, sizeof(*rx_stat));
+ for (i=0; i<session->stream_cnt; ++i) {
+ pjmedia_session_pause_stream(session, i, dir);
}
- return stat_cnt ? 0 : -1;
+ return PJ_SUCCESS;
}
+
/**
- * Modify stream, only when stream is inactive.
+ * Suspend receipt and transmission of individual stream in media session.
*/
-PJ_DEF(pj_status_t)
-pj_media_session_modify_stream (pj_media_session_t *session, unsigned index,
- unsigned modify_flag, const pj_media_stream_info *info)
+PJ_DEF(pj_status_t) pjmedia_session_pause_stream( pjmedia_session *session,
+ unsigned index,
+ pjmedia_dir dir)
{
- pj_media_stream_desc *sd;
-
- if (index >= session->stream_cnt) {
- pj_assert(0);
- return -1;
- }
-
- sd = session->stream_desc[index];
-
- if (sd->enc_stream || sd->dec_stream) {
- pj_assert(0);
- return -1;
- }
-
- if (modify_flag & PJ_MEDIA_STREAM_MODIFY_DIR) {
- sd->info.dir = info->dir;
- }
+ PJ_ASSERT_RETURN(session && index < session->stream_cnt, PJ_EINVAL);
- return 0;
+ return pjmedia_stream_pause(session->stream[index], dir);
}
+
/**
- * Activate media session.
+ * Activate individual stream in media session.
+ *
*/
-PJ_DEF(pj_status_t)
-pj_media_session_activate (pj_media_session_t *session)
+PJ_DEF(pj_status_t) pjmedia_session_resume_stream( pjmedia_session *session,
+ unsigned index,
+ pjmedia_dir dir)
{
- unsigned i;
- pj_status_t status = 0;
+ PJ_ASSERT_RETURN(session && index < session->stream_cnt, PJ_EINVAL);
- for (i=0; i<session->stream_cnt; ++i) {
- pj_status_t rc;
- rc = pj_media_session_activate_stream (session, i);
- if (status == 0)
- status = rc;
- }
- return status;
+ return pjmedia_stream_resume(session->stream[index], dir);
}
/**
- * Activate individual stream in media session.
+ * Enumerate media stream in the session.
*/
-PJ_DEF(pj_status_t)
-pj_media_session_activate_stream (pj_media_session_t *session, unsigned index)
+PJ_DEF(pj_status_t) pjmedia_session_enum_streams(const pjmedia_session *session,
+ unsigned *count,
+ pjmedia_stream_info info[])
{
- pj_media_stream_desc *sd;
- pj_media_stream_create_param scp;
- pj_status_t status;
- pj_time_val tv;
-
- if (index < 0 || index >= session->stream_cnt) {
- pj_assert(0);
- return -1;
- }
+ unsigned i;
- sd = session->stream_desc[index];
+ PJ_ASSERT_RETURN(session && count && *count && info, PJ_EINVAL);
- if (sd->enc_stream || sd->dec_stream) {
- /* Stream already active. */
- pj_assert(0);
- return 0;
- }
+ if (*count > session->stream_cnt)
+ *count = session->stream_cnt;
- pj_gettimeofday(&tv);
-
- /* Initialize parameter to create stream. */
- pj_memset (&scp, 0, sizeof(scp));
- scp.codec_id = &sd->info.fmt[0];
- scp.mediamgr = session->mediamgr;
- scp.dir = sd->info.dir;
- scp.rtp_sock = sd->info.sock_info.rtp_sock;
- scp.rtcp_sock = sd->info.sock_info.rtcp_sock;
- scp.remote_addr = pj_pool_calloc (session->pool, 1, sizeof(pj_sockaddr_in));
- pj_sockaddr_in_init(scp.remote_addr, &sd->info.rem_addr, sd->info.rem_port);
- scp.ssrc = tv.sec;
- scp.jb_min = 1;
- scp.jb_max = 15;
- scp.jb_maxcnt = 16;
-
- /* Build the stream! */
- status = pj_media_stream_create (session->pool, &sd->enc_stream, &sd->dec_stream, &scp);
-
- if (status==0 && sd->enc_stream) {
- status = pj_media_stream_start (sd->enc_stream);
- if (status != 0)
- goto on_error;
+ for (i=0; i<*count; ++i) {
+ pj_memcpy(&info[i], &session->stream[i], sizeof(pjmedia_stream_info));
}
- if (status==0 && sd->dec_stream) {
- status = pj_media_stream_start (sd->dec_stream);
- if (status != 0)
- goto on_error;
- }
- return status;
-on_error:
- if (sd->enc_stream) {
- pj_media_stream_destroy (sd->enc_stream);
- sd->enc_stream = NULL;
- }
- if (sd->dec_stream) {
- pj_media_stream_destroy (sd->dec_stream);
- sd->dec_stream = NULL;
- }
- return status;
+ return PJ_SUCCESS;
}
/**
- * Destroy media session.
+ * Get statistics
*/
-PJ_DEF(pj_status_t)
-pj_media_session_destroy (pj_media_session_t *session)
+PJ_DEF(pj_status_t) pjmedia_session_get_stat(const pjmedia_session *session,
+ unsigned *count,
+ pjmedia_stream_stat stat[])
{
- unsigned i;
+ PJ_ASSERT_RETURN(session && count && *count && stat, PJ_EINVAL);
- if (!session)
- return -1;
+ *count = 0;
+ pj_memset(stat, 0, *count * sizeof(pjmedia_stream_stat));
+ return PJ_EINVALIDOP;
+}
- for (i=0; i<session->stream_cnt; ++i) {
- pj_media_stream_desc *sd = session->stream_desc[i];
- if (sd->enc_stream) {
- pj_media_stream_destroy (sd->enc_stream);
- sd->enc_stream = NULL;
- }
- if (sd->dec_stream) {
- pj_media_stream_destroy (sd->dec_stream);
- sd->dec_stream = NULL;
- }
- }
- pj_pool_release (session->pool);
- return 0;
+/**
+ * Get individual stream statistic.
+ */
+PJ_DEF(pj_status_t) pjmedia_session_get_stream_stat( const pjmedia_session *s,
+ unsigned index,
+ pjmedia_stream_stat *stat)
+{
+ PJ_ASSERT_RETURN(s && index < s->stream_cnt && stat, PJ_EINVAL);
+ pj_memset(stat, 0, sizeof(pjmedia_stream_stat));
+ return PJ_EINVALIDOP;
}
+
diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index 323e0415..5846e27e 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -31,12 +31,13 @@
#include <stdlib.h>
-#define THISFILE "stream.c"
-#define ERRLEVEL 1
+#define THIS_FILE "stream.c"
+#define ERRLEVEL 1
+#define TRACE_(expr) PJ_LOG(3,expr)
-#define PJ_MAX_FRAME_DURATION_MS 200
-#define PJ_MAX_BUFFER_SIZE_MS 2000
-#define PJ_MAX_MTU 1500
+#define PJMEDIA_MAX_FRAME_DURATION_MS 200
+#define PJMEDIA_MAX_BUFFER_SIZE_MS 2000
+#define PJMEDIA_MAX_MTU 1500
struct jb_frame
{
@@ -48,196 +49,218 @@ struct jb_frame
#define pj_fifobuf_unalloc(fifo,buf) free(buf)
#define pj_fifobuf_free(fifo, buf) free(buf)
-enum stream_state
+
+/**
+ * Media channel.
+ */
+struct pjmedia_channel
{
- STREAM_STOPPED,
- STREAM_STARTED,
+ pjmedia_stream *stream; /**< Parent stream. */
+ pjmedia_dir dir; /**< Channel direction. */
+ unsigned pt; /**< Payload type. */
+ pj_bool_t paused; /**< Paused?. */
+ pj_snd_stream_info snd_info; /**< Sound stream param. */
+ pj_snd_stream *snd_stream; /**< Sound stream. */
+ unsigned in_pkt_size; /**< Size of input buffer. */
+ void *in_pkt; /**< Input buffer. */
+ unsigned out_pkt_size; /**< Size of output buffer. */
+ void *out_pkt; /**< Output buffer. */
+ unsigned pcm_buf_size; /**< Size of PCM buffer. */
+ void *pcm_buf; /**< PCM buffer. */
+ pj_rtp_session rtp; /**< RTP session. */
};
-struct pj_media_stream_t
+
+/**
+ * This structure describes media stream.
+ * A media stream is bidirectional media transmission between two endpoints.
+ * It consists of two channels, i.e. encoding and decoding channels.
+ * A media stream corresponds to a single "m=" line in a SDP session
+ * description.
+ */
+struct pjmedia_stream
{
- pj_media_dir_t dir;
- int pt;
- int state;
- pj_media_stream_stat stat;
- pj_media_stream_t *peer;
- pj_snd_stream_info snd_info;
- pj_snd_stream *snd_stream;
- pj_mutex_t *mutex;
- unsigned in_pkt_size;
- void *in_pkt;
- unsigned out_pkt_size;
- void *out_pkt;
- unsigned pcm_buf_size;
- void *pcm_buf;
- //pj_fifobuf_t fifobuf;
- pj_codec_mgr *codec_mgr;
- pj_codec *codec;
- pj_rtp_session rtp;
- pj_rtcp_session *rtcp;
- pj_jitter_buffer *jb;
- pj_sock_t rtp_sock;
- pj_sock_t rtcp_sock;
- pj_sockaddr_in dst_addr;
- pj_thread_t *transport_thread;
- int thread_quit_flag;
+ pjmedia_channel *enc; /**< Encoding channel. */
+ pjmedia_channel *dec; /**< Decoding channel. */
+
+ pjmedia_dir dir; /**< Stream direction. */
+ pjmedia_stream_stat stat; /**< Stream statistics. */
+
+ pjmedia_codec_mgr *codec_mgr; /**< Codec manager instance. */
+ pjmedia_codec *codec; /**< Codec instance being used. */
+
+ pj_mutex_t *jb_mutex;
+ pj_jitter_buffer jb; /**< Jitter buffer. */
+
+ pj_sock_t rtp_sock; /**< RTP socket. */
+ pj_sock_t rtcp_sock; /**< RTCP socket. */
+ pj_sockaddr_in dst_addr; /**< Destination RTP address. */
+
+ pj_rtcp_session rtcp; /**< RTCP for incoming RTP. */
+
+ pj_bool_t quit_flag; /**< To signal thread exit. */
+ pj_thread_t *thread; /**< Jitter buffer's thread. */
};
+
+/*
+ * play_callback()
+ *
+ * This callback is called by sound device's player thread when it
+ * needs to feed the player with some frames.
+ */
static pj_status_t play_callback(/* in */ void *user_data,
/* in */ pj_uint32_t timestamp,
/* out */ void *frame,
/*inout*/ unsigned size)
{
- pj_media_stream_t *channel = user_data;
+ pjmedia_channel *channel = user_data;
+ pjmedia_stream *stream = channel->stream;
struct jb_frame *jb_frame;
void *p;
pj_uint32_t extseq;
pj_status_t status;
- struct pj_audio_frame frame_in, frame_out;
+ struct pjmedia_frame frame_in, frame_out;
PJ_UNUSED_ARG(timestamp);
- /* Lock mutex */
- pj_mutex_lock (channel->mutex);
-
- if (!channel->codec) {
- pj_mutex_unlock (channel->mutex);
+ /* Do nothing if we're quitting. */
+ if (stream->quit_flag)
return -1;
- }
+
+ /* Lock jitter buffer mutex */
+ pj_mutex_lock( stream->jb_mutex );
/* Get frame from jitter buffer. */
- status = pj_jb_get (channel->jb, &extseq, &p);
+ status = pj_jb_get(&stream->jb, &extseq, &p);
+
+ /* Unlock jitter buffer mutex. */
+ pj_mutex_unlock( stream->jb_mutex );
+
jb_frame = p;
- if (status != 0 || jb_frame == NULL) {
+ if (status != PJ_SUCCESS || jb_frame == NULL) {
pj_memset(frame, 0, size);
- pj_mutex_unlock(channel->mutex);
return 0;
}
/* Decode */
frame_in.buf = jb_frame->buf;
frame_in.size = jb_frame->size;
- frame_in.type = PJ_AUDIO_FRAME_AUDIO; /* ignored */
+ frame_in.type = PJMEDIA_FRAME_TYPE_AUDIO; /* ignored */
frame_out.buf = channel->pcm_buf;
- status = channel->codec->op->decode (channel->codec, &frame_in,
- channel->pcm_buf_size, &frame_out);
+ status = stream->codec->op->decode( stream->codec, &frame_in,
+ channel->pcm_buf_size, &frame_out);
if (status != 0) {
- PJ_LOG(3, (THISFILE, "decode() has return error status %d",
- status));
+ TRACE_((THIS_FILE, "decode() has return error status %d", status));
pj_memset(frame, 0, size);
pj_fifobuf_free (&channel->fifobuf, jb_frame);
- pj_mutex_unlock(channel->mutex);
return 0;
}
/* Put in sound buffer. */
if (frame_out.size > size) {
- PJ_LOG(3, (THISFILE, "Sound playout buffer truncated %d bytes",
- frame_out.size - size));
+ TRACE_((THIS_FILE, "Sound playout buffer truncated %d bytes",
+ frame_out.size - size));
frame_out.size = size;
}
pj_memcpy(frame, frame_out.buf, size);
-
pj_fifobuf_free (&channel->fifobuf, jb_frame);
- pj_mutex_unlock(channel->mutex);
+
return 0;
}
+
+/**
+ * rec_callback()
+ *
+ * This callback is called when the mic device has gathered
+ * enough audio samples. We will encode the audio samples and
+ * send it to remote.
+ */
static pj_status_t rec_callback( /* in */ void *user_data,
/* in */ pj_uint32_t timestamp,
/* in */ const void *frame,
/* in */ unsigned size)
{
- pj_media_stream_t *channel = user_data;
+ pjmedia_channel *channel = user_data;
+ pjmedia_stream *stream = channel->stream;
pj_status_t status = 0;
- struct pj_audio_frame frame_in, frame_out;
+ struct pjmedia_frame frame_in, frame_out;
int ts_len;
void *rtphdr;
int rtphdrlen;
pj_ssize_t sent;
-#if 0
- static FILE *fhnd = NULL;
-#endif
- PJ_UNUSED_ARG(timestamp);
- /* Start locking channel mutex */
- pj_mutex_lock (channel->mutex);
+ PJ_UNUSED_ARG(timestamp);
- if (!channel->codec) {
- status = -1;
- goto on_return;
- }
+ /* Check if stream is quitting. */
+ if (stream->quit_flag)
+ return -1;
/* Encode. */
- frame_in.type = PJ_MEDIA_TYPE_AUDIO;
+ frame_in.type = PJMEDIA_TYPE_AUDIO;
frame_in.buf = (void*)frame;
frame_in.size = size;
frame_out.buf = ((char*)channel->out_pkt) + sizeof(pj_rtp_hdr);
- status = channel->codec->op->encode (channel->codec, &frame_in,
- channel->out_pkt_size - sizeof(pj_rtp_hdr),
- &frame_out);
+ status = stream->codec->op->encode( stream->codec, &frame_in,
+ channel->out_pkt_size - sizeof(pj_rtp_hdr),
+ &frame_out);
if (status != 0) {
- PJ_LOG(3,(THISFILE, "Codec encode() has returned error status %d",
- status));
- goto on_return;
+ TRACE_((THIS_FILE, "Codec encode() has returned error status %d",
+ status));
+ return status;
}
/* Encapsulate. */
ts_len = size / (channel->snd_info.bits_per_sample / 8);
- status = pj_rtp_encode_rtp (&channel->rtp, channel->pt, 0,
+ status = pj_rtp_encode_rtp( &channel->rtp,
+ channel->pt, 0,
frame_out.size, ts_len,
(const void**)&rtphdr, &rtphdrlen);
if (status != 0) {
- PJ_LOG(3,(THISFILE, "RTP encode_rtp() has returned error status %d",
- status));
- goto on_return;
+ TRACE_((THIS_FILE, "RTP encode_rtp() has returned error status %d",
+ status));
+ return status;
}
if (rtphdrlen != sizeof(pj_rtp_hdr)) {
/* We don't support RTP with extended header yet. */
PJ_TODO(SUPPORT_SENDING_RTP_WITH_EXTENDED_HEADER);
- PJ_LOG(3,(THISFILE, "Unsupported extended RTP header for transmission"));
- goto on_return;
+ TRACE_((THIS_FILE, "Unsupported extended RTP header for transmission"));
+ return 0;
}
pj_memcpy(channel->out_pkt, rtphdr, sizeof(pj_rtp_hdr));
/* Send. */
sent = frame_out.size+sizeof(pj_rtp_hdr);
- status = pj_sock_sendto (channel->rtp_sock, channel->out_pkt, &sent, 0,
- &channel->dst_addr, sizeof(channel->dst_addr));
+ status = pj_sock_sendto(stream->rtp_sock, channel->out_pkt, &sent, 0,
+ &stream->dst_addr, sizeof(stream->dst_addr));
if (status != PJ_SUCCESS)
- goto on_return;
+ return status;
/* Update stat */
- channel->stat.pkt_tx++;
- channel->stat.oct_tx += frame_out.size+sizeof(pj_rtp_hdr);
-
-#if 0
- if (fhnd == NULL) {
- fhnd = fopen("RTP.DAT", "wb");
- if (fhnd) {
- fwrite (channel->out_pkt, frame_out.size+sizeof(pj_rtp_hdr), 1, fhnd);
- fclose(fhnd);
- }
- }
-#endif
+ stream->stat.enc.pkt++;
+ stream->stat.enc.bytes += frame_out.size+sizeof(pj_rtp_hdr);
-on_return:
- pj_mutex_unlock (channel->mutex);
- return status;
+ return 0;
}
-static int PJ_THREAD_FUNC stream_decoder_transport_thread (void*arg)
+/*
+ * This thread will poll the socket for incoming packets, and put
+ * the packets to jitter buffer.
+ */
+static int PJ_THREAD_FUNC jitter_buffer_thread (void*arg)
{
- pj_media_stream_t *channel = arg;
+ pjmedia_stream *stream = arg;
+ pjmedia_channel *channel = stream->dec;
- while (!channel->thread_quit_flag) {
+ while (!stream->quit_flag) {
pj_ssize_t len, size;
const pj_rtp_hdr *hdr;
const void *payload;
@@ -250,64 +273,64 @@ static int PJ_THREAD_FUNC stream_decoder_transport_thread (void*arg)
pj_time_val timeout;
PJ_FD_ZERO (&fds);
- PJ_FD_SET (channel->rtp_sock, &fds);
+ PJ_FD_SET (stream->rtp_sock, &fds);
timeout.sec = 0;
- timeout.msec = 100;
+ timeout.msec = 1;
/* Wait with timeout. */
- status = pj_sock_select(channel->rtp_sock, &fds, NULL, NULL, &timeout);
+ status = pj_sock_select(stream->rtp_sock, &fds, NULL, NULL, &timeout);
if (status != 1)
continue;
/* Get packet from socket. */
len = channel->in_pkt_size;
- status = pj_sock_recv (channel->rtp_sock, channel->in_pkt, &len, 0);
+ status = pj_sock_recv(stream->rtp_sock, channel->in_pkt, &len, 0);
if (len < 1 || status != PJ_SUCCESS) {
if (pj_get_netos_error() == PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) {
- /* On Win2K SP2 (or above) and WinXP, recv() will get WSAECONNRESET
- when the sending side receives ICMP port unreachable.
+ /* On Win2K SP2 (or above) and WinXP, recv() will get
+ * WSAECONNRESET when the sending side receives ICMP port
+ * unreachable.
*/
continue;
}
- //pj_perror(THISFILE, "Error receiving packet from socket (len=%d)", len);
pj_thread_sleep(1);
continue;
}
- if (channel->state != STREAM_STARTED)
+ if (channel->paused)
continue;
- if (channel->thread_quit_flag)
- break;
-
- /* Start locking the channel. */
- pj_mutex_lock (channel->mutex);
-
/* Update RTP and RTCP session. */
- status = pj_rtp_decode_rtp (&channel->rtp, channel->in_pkt, len, &hdr, &payload, &payloadlen);
- if (status != 0) {
- pj_mutex_unlock (channel->mutex);
- PJ_LOG(4,(THISFILE, "RTP decode_rtp() has returned error status %d", status));
+ status = pj_rtp_decode_rtp(&channel->rtp, channel->in_pkt, len,
+ &hdr, &payload, &payloadlen);
+ if (status != PJ_SUCCESS) {
+ TRACE_((THIS_FILE, "RTP decode_rtp() has returned error status %d",
+ status));
continue;
}
- status = pj_rtp_session_update (&channel->rtp, hdr);
- if (status != 0 && status != PJ_RTP_ERR_SESSION_PROBATION && status != PJ_RTP_ERR_SESSION_RESTARTED) {
- pj_mutex_unlock (channel->mutex);
- PJ_LOG(4,(THISFILE, "RTP session_update() has returned error status %d", status));
+
+ status = pj_rtp_session_update(&channel->rtp, hdr);
+ if (status != 0 &&
+ status != PJMEDIA_RTP_ERR_SESSION_PROBATION &&
+ status != PJMEDIA_RTP_ERR_SESSION_RESTARTED)
+ {
+ TRACE_((THIS_FILE,
+ "RTP session_update() has returned error status %d",
+ status));
continue;
}
- pj_rtcp_rx_rtp (channel->rtcp, pj_ntohs(hdr->seq), pj_ntohl(hdr->ts));
+ pj_rtcp_rx_rtp(&stream->rtcp, pj_ntohs(hdr->seq), pj_ntohl(hdr->ts));
/* Update stat */
- channel->stat.pkt_rx++;
- channel->stat.oct_rx += len;
+ stream->stat.dec.pkt++;
+ stream->stat.dec.bytes += len;
/* Copy to FIFO buffer. */
size = payloadlen+sizeof(struct jb_frame);
jb_frame = pj_fifobuf_alloc (&channel->fifobuf, size);
if (jb_frame == NULL) {
- pj_mutex_unlock (channel->mutex);
- PJ_LOG(4,(THISFILE, "Unable to allocate %d bytes FIFO buffer", size));
+ TRACE_((THIS_FILE, "Unable to allocate %d bytes FIFO buffer",
+ size));
continue;
}
@@ -317,141 +340,109 @@ static int PJ_THREAD_FUNC stream_decoder_transport_thread (void*arg)
pj_memcpy (jb_frame->buf, payload, payloadlen);
/* Put to jitter buffer. */
- status = pj_jb_put (channel->jb, pj_ntohs(hdr->seq), jb_frame);
+ pj_mutex_lock( stream->jb_mutex );
+ status = pj_jb_put(&stream->jb, pj_ntohs(hdr->seq), jb_frame);
+ pj_mutex_unlock( stream->jb_mutex );
+
if (status != 0) {
pj_fifobuf_unalloc (&channel->fifobuf, jb_frame);
- pj_mutex_unlock (channel->mutex);
- PJ_LOG(4,(THISFILE, "Jitter buffer put() has returned error status %d", status));
+
+ TRACE_((THIS_FILE,
+ "Jitter buffer put() has returned error status %d",
+ status));
continue;
}
-
- pj_mutex_unlock (channel->mutex);
}
return 0;
}
-static void init_snd_param_from_codec_attr (pj_snd_stream_info *param,
- const pj_codec_attr *attr)
+
+/*
+ * Create sound stream parameter from codec attributes.
+ */
+static void init_snd_param( pj_snd_stream_info *snd_param,
+ const pjmedia_codec_param *codec_param)
{
- param->bits_per_sample = attr->pcm_bits_per_sample;
- param->bytes_per_frame = 2;
- param->frames_per_packet = attr->sample_rate * attr->ptime / 1000;
- param->samples_per_frame = 1;
- param->samples_per_sec = attr->sample_rate;
+ pj_memset(snd_param, 0, sizeof(*snd_param));
+
+ snd_param->bits_per_sample = codec_param->pcm_bits_per_sample;
+ snd_param->bytes_per_frame = 2;
+ snd_param->frames_per_packet = codec_param->sample_rate *
+ codec_param->ptime /
+ 1000;
+ snd_param->samples_per_frame = 1;
+ snd_param->samples_per_sec = codec_param->sample_rate;
}
-static pj_media_stream_t *create_channel ( pj_pool_t *pool,
- pj_media_dir_t dir,
- pj_media_stream_t *peer,
- pj_codec_id *codec_id,
- pj_media_stream_create_param *param)
+
+/*
+ * Create media channel.
+ */
+static pj_status_t create_channel( pj_pool_t *pool,
+ pjmedia_stream *stream,
+ pjmedia_dir dir,
+ const pjmedia_stream_info *param,
+ const pjmedia_codec_param *codec_param,
+ pjmedia_channel **p_channel)
{
- pj_media_stream_t *channel;
- pj_codec_attr codec_attr;
- void *ptr;
- unsigned size;
+ pjmedia_channel *channel;
pj_status_t status;
/* Allocate memory for channel descriptor */
- size = sizeof(pj_media_stream_t);
- channel = pj_pool_calloc(pool, 1, size);
- if (!channel) {
- PJ_LOG(1,(THISFILE, "Unable to allocate %u bytes channel descriptor",
- size));
- return NULL;
- }
-
- channel->dir = dir;
- channel->pt = codec_id->pt;
- channel->peer = peer;
- channel->codec_mgr = pj_med_mgr_get_codec_mgr (param->mediamgr);
- channel->rtp_sock = param->rtp_sock;
- channel->rtcp_sock = param->rtcp_sock;
- channel->dst_addr = *param->remote_addr;
- channel->state = STREAM_STOPPED;
-
- /* Create mutex for the channel. */
- status = pj_mutex_create_simple(pool, NULL, &channel->mutex);
- if (status != PJ_SUCCESS)
- goto err_cleanup;
- /* Create and initialize codec, only if peer is not present.
- We only use one codec instance for both encoder and decoder.
- */
- if (peer && peer->codec) {
- channel->codec = peer->codec;
- status = channel->codec->factory->op->default_attr(channel->codec->factory, codec_id,
- &codec_attr);
- if (status != 0) {
- goto err_cleanup;
- }
+ channel = pj_pool_zalloc(pool, sizeof(pjmedia_channel));
+ PJ_ASSERT_RETURN(channel != NULL, PJ_ENOMEM);
- } else {
- channel->codec = pj_codec_mgr_alloc_codec(channel->codec_mgr, codec_id);
- if (channel->codec == NULL) {
- goto err_cleanup;
- }
-
- status = channel->codec->factory->op->default_attr(channel->codec->factory, codec_id,
- &codec_attr);
- if (status != 0) {
- goto err_cleanup;
- }
+ /* Init channel info. */
- codec_attr.pt = codec_id->pt;
- status = channel->codec->op->open(channel->codec, &codec_attr);
- if (status != 0) {
- goto err_cleanup;
- }
- }
+ channel->stream = stream;
+ channel->dir = dir;
+ channel->paused = 1;
+ channel->pt = param->fmt.pt;
/* Allocate buffer for incoming packet. */
- channel->in_pkt_size = PJ_MAX_MTU;
- channel->in_pkt = pj_pool_alloc(pool, channel->in_pkt_size);
- if (!channel->in_pkt) {
- PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes incoming packet buffer",
- channel->in_pkt_size));
- goto err_cleanup;
- }
+ channel->in_pkt_size = PJMEDIA_MAX_MTU;
+ channel->in_pkt = pj_pool_alloc( pool, channel->in_pkt_size );
+ PJ_ASSERT_RETURN(channel->in_pkt != NULL, PJ_ENOMEM);
+
+
/* Allocate buffer for outgoing packet. */
+
channel->out_pkt_size = sizeof(pj_rtp_hdr) +
- codec_attr.avg_bps / 8 * PJ_MAX_FRAME_DURATION_MS / 1000;
- if (channel->out_pkt_size > PJ_MAX_MTU)
- channel->out_pkt_size = PJ_MAX_MTU;
+ codec_param->avg_bps/8 *
+ PJMEDIA_MAX_FRAME_DURATION_MS /
+ 1000;
+
+ if (channel->out_pkt_size > PJMEDIA_MAX_MTU)
+ channel->out_pkt_size = PJMEDIA_MAX_MTU;
+
channel->out_pkt = pj_pool_alloc(pool, channel->out_pkt_size);
- if (!channel->out_pkt) {
- PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes encoding buffer",
- channel->out_pkt_size));
- goto err_cleanup;
- }
+ PJ_ASSERT_RETURN(channel->out_pkt != NULL, PJ_ENOMEM);
+
+
+ /* Allocate buffer for decoding to PCM: */
- /* Allocate buffer for decoding to PCM */
- channel->pcm_buf_size = codec_attr.sample_rate *
- codec_attr.pcm_bits_per_sample / 8 *
- PJ_MAX_FRAME_DURATION_MS / 1000;
+ channel->pcm_buf_size = codec_param->sample_rate *
+ codec_param->pcm_bits_per_sample / 8 *
+ PJMEDIA_MAX_FRAME_DURATION_MS / 1000;
channel->pcm_buf = pj_pool_alloc (pool, channel->pcm_buf_size);
- if (!channel->pcm_buf) {
- PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes PCM buffer",
- channel->pcm_buf_size));
- goto err_cleanup;
- }
+ PJ_ASSERT_RETURN(channel->pcm_buf != NULL, PJ_ENOMEM);
- /* Allocate buffer for frames put in jitter buffer. */
- size = codec_attr.avg_bps / 8 * PJ_MAX_BUFFER_SIZE_MS / 1000;
- ptr = pj_pool_alloc(pool, size);
- if (!ptr) {
- PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes jitter buffer",
- channel->pcm_buf_size));
- goto err_cleanup;
- }
- //pj_fifobuf_init (&channel->fifobuf, ptr, size);
+
+ /* Create RTP and RTCP sessions: */
+
+ status = pj_rtp_session_init(&channel->rtp, param->fmt.pt,
+ param->ssrc);
+ if (status != PJ_SUCCESS)
+ return status;
/* Create and initialize sound device */
- init_snd_param_from_codec_attr (&channel->snd_info, &codec_attr);
- if (dir == PJ_MEDIA_DIR_ENCODING)
+ init_snd_param(&channel->snd_info, codec_param);
+
+ if (dir == PJMEDIA_DIR_ENCODING)
channel->snd_stream = pj_snd_open_recorder(-1, &channel->snd_info,
&rec_callback, channel);
else
@@ -459,189 +450,249 @@ static pj_media_stream_t *create_channel ( pj_pool_t *pool,
&play_callback, channel);
if (!channel->snd_stream)
+ return -1;
+
+
+ /* Done. */
+ *p_channel = channel;
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Create media stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_create( pjmedia_endpt *endpt,
+ pj_pool_t *pool,
+ const pjmedia_stream_info *info,
+ pjmedia_stream **p_stream)
+
+{
+ pjmedia_stream *stream;
+ pjmedia_codec_param codec_param;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(pool && info && p_stream, PJ_EINVAL);
+
+
+ /* Allocate the media stream: */
+
+ stream = pj_pool_zalloc(pool, sizeof(pjmedia_stream));
+ PJ_ASSERT_RETURN(stream != NULL, PJ_ENOMEM);
+
+
+ /* Init stream: */
+
+ stream->dir = info->dir;
+ stream->codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
+
+ /* Create mutex to protect jitter buffer: */
+
+ status = pj_mutex_create_simple(pool, NULL, &stream->jb_mutex);
+ if (status != PJ_SUCCESS)
goto err_cleanup;
- /* Create RTP and RTCP sessions. */
- if (pj_rtp_session_init(&channel->rtp, codec_id->pt, param->ssrc) != 0) {
- PJ_LOG(1, (THISFILE, "RTP session initialization error"));
+
+ /* Create and initialize codec: */
+
+ status = pjmedia_codec_mgr_alloc_codec( stream->codec_mgr,
+ &info->fmt, &stream->codec);
+ if (status != PJ_SUCCESS)
goto err_cleanup;
- }
- /* For decoder, create RTCP session, jitter buffer, and transport thread. */
- if (dir == PJ_MEDIA_DIR_DECODING) {
- channel->rtcp = pj_pool_calloc(pool, 1, sizeof(pj_rtcp_session));
- if (!channel->rtcp) {
- PJ_LOG(1, (THISFILE, "Unable to allocate RTCP session"));
- goto err_cleanup;
- }
- pj_rtcp_init(channel->rtcp, param->ssrc);
+ /* Get default codec param: */
- channel->jb = pj_pool_calloc(pool, 1, sizeof(pj_jitter_buffer));
- if (!channel->jb) {
- PJ_LOG(1, (THISFILE, "Unable to allocate jitter buffer descriptor"));
- goto err_cleanup;
- }
- if (pj_jb_init(channel->jb, pool, param->jb_min, param->jb_max, param->jb_maxcnt)) {
- PJ_LOG(1, (THISFILE, "Unable to allocate jitter buffer"));
- goto err_cleanup;
- }
+ status = stream->codec->op->default_attr(stream->codec, &codec_param);
+ if (status != PJ_SUCCESS)
+ goto err_cleanup;
- status = pj_thread_create(pool, "decode",
- &stream_decoder_transport_thread, channel,
- 0, 0, &channel->transport_thread);
- if (status != PJ_SUCCESS) {
- //pj_perror(THISFILE, "Unable to create transport thread");
- goto err_cleanup;
- }
- }
- /* Done. */
- return channel;
+ /* Open the codec: */
+
+ status = stream->codec->op->open(stream->codec, &codec_param);
+ if (status != PJ_SUCCESS)
+ goto err_cleanup;
+
+
+ /* Init RTCP session: */
+
+ pj_rtcp_init(&stream->rtcp, info->ssrc);
+
+
+ /* Init jitter buffer: */
+
+ status = pj_jb_init(&stream->jb, pool,
+ info->jb_min, info->jb_max, info->jb_maxcnt);
+ if (status != PJ_SUCCESS)
+ goto err_cleanup;
+
+
+ /* Create jitter buffer thread: */
+
+ status = pj_thread_create(pool, "decode",
+ &jitter_buffer_thread, stream,
+ 0, 0, &stream->thread);
+ if (status != PJ_SUCCESS)
+ goto err_cleanup;
+
+
+ /* Create decoder channel: */
+
+ status = create_channel( pool, stream, PJMEDIA_DIR_DECODING, info,
+ &codec_param, &stream->dec);
+ if (status != PJ_SUCCESS)
+ goto err_cleanup;
+
+
+ /* Create encoder channel: */
+
+ status = create_channel( pool, stream, PJMEDIA_DIR_ENCODING, info,
+ &codec_param, &stream->enc);
+ if (status != PJ_SUCCESS)
+ goto err_cleanup;
+
+
+ /* Success! */
+ *p_stream = stream;
+ return PJ_SUCCESS;
+
err_cleanup:
- pj_media_stream_destroy(channel);
- return NULL;
+ pjmedia_stream_destroy(stream);
+ return status;
}
-PJ_DEF(pj_status_t) pj_media_stream_create (pj_pool_t *pool,
- pj_media_stream_t **enc_stream,
- pj_media_stream_t **dec_stream,
- pj_media_stream_create_param *param)
+/*
+ * Destroy stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_destroy( pjmedia_stream *stream )
{
- *dec_stream = *enc_stream = NULL;
- if (param->dir & PJ_MEDIA_DIR_DECODING) {
- *dec_stream =
- create_channel(pool, PJ_MEDIA_DIR_DECODING, NULL, param->codec_id, param);
- if (!*dec_stream)
- return -1;
+ PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+
+ /* Signal threads to quit. */
+
+ stream->quit_flag = 1;
+
+
+ /* Close encoding sound stream. */
+
+ if (stream->enc && stream->enc->snd_stream) {
+
+ pj_snd_stream_stop(stream->enc->snd_stream);
+ pj_snd_stream_close(stream->enc->snd_stream);
+ stream->enc->snd_stream = NULL;
+
}
- if (param->dir & PJ_MEDIA_DIR_ENCODING) {
- *enc_stream =
- create_channel(pool, PJ_MEDIA_DIR_ENCODING, *dec_stream, param->codec_id, param);
- if (!*enc_stream) {
- if (*dec_stream) {
- pj_media_stream_destroy(*dec_stream);
- *dec_stream = NULL;
- }
- return -1;
- }
+ /* Close decoding sound stream. */
+
+ if (stream->dec && stream->dec->snd_stream) {
+
+ pj_snd_stream_stop(stream->dec->snd_stream);
+ pj_snd_stream_close(stream->dec->snd_stream);
+ stream->dec->snd_stream = NULL;
- if (*dec_stream) {
- (*dec_stream)->peer = *enc_stream;
- }
}
- return 0;
-}
+ /* Wait for jitter buffer thread to quit: */
-PJ_DEF(pj_status_t) pj_media_stream_start (pj_media_stream_t *channel)
-{
- pj_status_t status;
+ if (stream->thread) {
+ pj_thread_join(stream->thread);
+ pj_thread_destroy(stream->thread);
+ stream->thread = NULL;
+ }
- status = pj_snd_stream_start(channel->snd_stream);
+ /* Free codec. */
- if (status == 0)
- channel->state = STREAM_STARTED;
- return status;
-}
+ if (stream->codec) {
+ stream->codec->op->close(stream->codec);
+ pjmedia_codec_mgr_dealloc_codec(stream->codec_mgr, stream->codec);
+ stream->codec = NULL;
+ }
-PJ_DEF(pj_status_t) pj_media_stream_get_stat (const pj_media_stream_t *stream,
- pj_media_stream_stat *stat)
-{
- if (stream->dir == PJ_MEDIA_DIR_ENCODING) {
- pj_memcpy (stat, &stream->stat, sizeof(*stat));
- } else {
- pj_rtcp_pkt *rtcp_pkt;
- int len;
-
- pj_memset (stat, 0, sizeof(*stat));
- pj_assert (stream->rtcp != 0);
- pj_rtcp_build_rtcp (stream->rtcp, &rtcp_pkt, &len);
-
- stat->pkt_rx = stream->stat.pkt_rx;
- stat->oct_rx = stream->stat.oct_rx;
-
- PJ_TODO(SUPPORT_JITTER_CALCULATION_FOR_NON_8KHZ_SAMPLE_RATE)
- stat->jitter = pj_ntohl(rtcp_pkt->rr.jitter) / 8;
- stat->pkt_lost = (rtcp_pkt->rr.total_lost_2 << 16) +
- (rtcp_pkt->rr.total_lost_1 << 8) +
- rtcp_pkt->rr.total_lost_0;
+ /* Free mutex */
+
+ if (stream->jb_mutex) {
+ pj_mutex_destroy(stream->jb_mutex);
+ stream->jb_mutex = NULL;
}
- return 0;
+
+ return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pj_media_stream_pause (pj_media_stream_t *channel)
+
+
+/*
+ * Start stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_start(pjmedia_stream *stream)
{
- PJ_UNUSED_ARG(channel);
- return -1;
+
+ PJ_ASSERT_RETURN(stream && stream->enc && stream->dec, PJ_EINVALIDOP);
+
+ if (stream->enc && (stream->dir & PJMEDIA_DIR_ENCODING)) {
+ stream->enc->paused = 0;
+ pj_snd_stream_start(stream->enc->snd_stream);
+ }
+
+ if (stream->dec && (stream->dir & PJMEDIA_DIR_DECODING)) {
+ stream->dec->paused = 0;
+ pj_snd_stream_start(stream->dec->snd_stream);
+ }
+
+ return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pj_media_stream_resume (pj_media_stream_t *channel)
+
+/*
+ * Get stream statistics.
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_get_stat( const pjmedia_stream *stream,
+ pjmedia_stream_stat *stat)
{
- PJ_UNUSED_ARG(channel);
- return -1;
+ PJ_ASSERT_RETURN(stream && stat, PJ_EINVAL);
+
+ pj_memcpy(stat, &stream->stat, sizeof(pjmedia_stream_stat));
+
+ return PJ_SUCCESS;
}
-PJ_DEF(pj_status_t) pj_media_stream_destroy (pj_media_stream_t *channel)
+
+/*
+ * Pause stream.
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_pause( pjmedia_stream *stream,
+ pjmedia_dir dir)
{
- channel->thread_quit_flag = 1;
+ PJ_ASSERT_RETURN(stream, PJ_EINVAL);
- pj_mutex_lock (channel->mutex);
- if (channel->peer)
- pj_mutex_lock (channel->peer->mutex);
+ if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc)
+ stream->enc->paused = 1;
- if (channel->jb) {
- /* No need to deinitialize jitter buffer. */
- }
- if (channel->transport_thread) {
- pj_thread_join(channel->transport_thread);
- pj_thread_destroy(channel->transport_thread);
- channel->transport_thread = NULL;
- }
- if (channel->snd_stream != NULL) {
- pj_mutex_unlock (channel->mutex);
- pj_snd_stream_stop(channel->snd_stream);
- pj_mutex_lock (channel->mutex);
- pj_snd_stream_close(channel->snd_stream);
- channel->snd_stream = NULL;
- }
- if (channel->codec) {
- channel->codec->op->close(channel->codec);
- pj_codec_mgr_dealloc_codec(channel->codec_mgr, channel->codec);
- channel->codec = NULL;
- }
- if (channel->peer) {
- pj_media_stream_t *peer = channel->peer;
- peer->peer = NULL;
- peer->codec = NULL;
- peer->thread_quit_flag = 1;
- if (peer->transport_thread) {
- pj_mutex_unlock (peer->mutex);
- pj_thread_join(peer->transport_thread);
- pj_mutex_lock (peer->mutex);
- pj_thread_destroy(peer->transport_thread);
- peer->transport_thread = NULL;
- }
- if (peer->snd_stream) {
- pj_mutex_unlock (peer->mutex);
- pj_snd_stream_stop(peer->snd_stream);
- pj_mutex_lock (peer->mutex);
- pj_snd_stream_close(peer->snd_stream);
- peer->snd_stream = NULL;
- }
- }
+ if ((dir & PJMEDIA_DIR_DECODING) && stream->dec)
+ stream->dec->paused = 1;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Resume stream
+ */
+PJ_DEF(pj_status_t) pjmedia_stream_resume( pjmedia_stream *stream,
+ pjmedia_dir dir)
+{
+ PJ_ASSERT_RETURN(stream, PJ_EINVAL);
- channel->state = STREAM_STOPPED;
+ if ((dir & PJMEDIA_DIR_ENCODING) && stream->enc)
+ stream->enc->paused = 1;
- if (channel->peer)
- pj_mutex_unlock (channel->peer->mutex);
- pj_mutex_unlock(channel->mutex);
- pj_mutex_destroy(channel->mutex);
+ if ((dir & PJMEDIA_DIR_DECODING) && stream->dec)
+ stream->dec->paused = 1;
- return 0;
+ return PJ_SUCCESS;
}
diff --git a/pjmedia/src/test/audio_tool.c b/pjmedia/src/test/audio_tool.c
index 074802be..d4b8ad2f 100644
--- a/pjmedia/src/test/audio_tool.c
+++ b/pjmedia/src/test/audio_tool.c
@@ -26,8 +26,8 @@ static pj_caching_pool caching_pool;
static pj_pool_factory *pf;
static FILE *fhnd;
static pj_med_mgr_t *mm;
-static pj_codec *codec;
-static pj_codec_attr cattr;
+static pjmedia_codec *codec;
+static pjmedia_codec_param cattr;
#define WRITE_ORIGINAL_PCM 0
@@ -60,14 +60,14 @@ static pj_status_t play_callback(/* in */ void *user_data,
/* out */ unsigned size)
{
char pkt[160];
- struct pj_audio_frame in, out;
+ struct pjmedia_frame in, out;
int frmsz = cattr.avg_bps / 8 * cattr.ptime / 1000;
if (fread(pkt, frmsz, 1, fhnd) != 1) {
puts("EOF");
return -1;
} else {
- in.type = PJ_AUDIO_FRAME_AUDIO;
+ in.type = PJMEDIA_FRAME_TYPE_AUDIO;
in.buf = pkt;
in.size = frmsz;
out.buf = frame;
@@ -85,14 +85,14 @@ static pj_status_t rec_callback( /* in */ void *user_data,
/* in*/ unsigned size)
{
char pkt[160];
- struct pj_audio_frame in, out;
+ struct pjmedia_frame in, out;
//int frmsz = cattr.avg_bps / 8 * cattr.ptime / 1000;
#if WRITE_ORIGINAL_PCM
fwrite(frame, size, 1, fhnd_pcm);
#endif
- in.type = PJ_AUDIO_FRAME_AUDIO;
+ in.type = PJMEDIA_FRAME_TYPE_AUDIO;
in.buf = (void*)frame;
in.size = size;
out.buf = pkt;
@@ -107,8 +107,8 @@ static pj_status_t rec_callback( /* in */ void *user_data,
static pj_status_t init()
{
- pj_codec_mgr *cm;
- pj_codec_id id;
+ pjmedia_codec_mgr *cm;
+ pjmedia_codec_info id;
int i;
pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);
@@ -129,12 +129,12 @@ static pj_status_t init()
mm = pj_med_mgr_create (&caching_pool.factory);
cm = pj_med_mgr_get_codec_mgr (mm);
- id.type = PJ_MEDIA_TYPE_AUDIO;
+ id.type = PJMEDIA_TYPE_AUDIO;
id.pt = 0;
id.encoding_name = pj_str("PCMU");
id.sample_rate = 8000;
- codec = pj_codec_mgr_alloc_codec (cm, &id);
+ codec = pjmedia_codec_mgr_alloc_codec (cm, &id);
codec->op->default_attr(codec, &cattr);
codec->op->open(codec, &cattr);
return 0;
@@ -142,10 +142,10 @@ static pj_status_t init()
static pj_status_t deinit()
{
- pj_codec_mgr *cm;
+ pjmedia_codec_mgr *cm;
cm = pj_med_mgr_get_codec_mgr (mm);
codec->op->close(codec);
- pj_codec_mgr_dealloc_codec (cm, codec);
+ pjmedia_codec_mgr_dealloc_codec (cm, codec);
pj_med_mgr_destroy (mm);
pj_caching_pool_destroy(&caching_pool);
return 0;
@@ -300,13 +300,13 @@ static int create_ses_by_remote_sdp(int local_port, char *sdp)
char *local_ip;
switch (info[i]->dir) {
- case PJ_MEDIA_DIR_NONE:
+ case PJMEDIA_DIR_NONE:
dir = "- NONE -"; break;
- case PJ_MEDIA_DIR_ENCODING:
+ case PJMEDIA_DIR_ENCODING:
dir = "SENDONLY"; break;
- case PJ_MEDIA_DIR_DECODING:
+ case PJMEDIA_DIR_DECODING:
dir = "RECVONLY"; break;
- case PJ_MEDIA_DIR_ENCODING_DECODING:
+ case PJMEDIA_DIR_ENCODING_DECODING:
dir = "SENDRECV"; break;
default:
dir = "?UNKNOWN"; break;
@@ -345,7 +345,7 @@ static pj_status_t convert(const char *src, const char *dst)
{
char pcm[320];
char frame[160];
- struct pj_audio_frame in, out;
+ struct pjmedia_frame in, out;
fhnd_pcm = fopen(src, "rb");
if (!fhnd_pcm)
@@ -356,7 +356,7 @@ static pj_status_t convert(const char *src, const char *dst)
while (fread(pcm, 320, 1, fhnd_pcm) == 1) {
- in.type = PJ_AUDIO_FRAME_AUDIO;
+ in.type = PJMEDIA_FRAME_TYPE_AUDIO;
in.buf = pcm;
in.size = 320;
out.buf = frame;
diff --git a/pjmedia/src/test/session_test.c b/pjmedia/src/test/session_test.c
index c106f04d..f1d57282 100644
--- a/pjmedia/src/test/session_test.c
+++ b/pjmedia/src/test/session_test.c
@@ -44,8 +44,8 @@ pj_status_t session_test (pj_pool_factory *pf)
s1 = pj_media_session_create (mm, NULL);
// Set caller's media to send-only.
- sd_info.dir = PJ_MEDIA_DIR_ENCODING;
- pj_media_session_modify_stream (s1, 0, PJ_MEDIA_STREAM_MODIFY_DIR, &sd_info);
+ sd_info.dir = PJMEDIA_DIR_ENCODING;
+ pj_media_session_modify_stream (s1, 0, PJMEDIA_STREAM_MODIFY_DIR, &sd_info);
// Create caller SDP.
sdp = pj_media_session_create_sdp (s1, pool, 0);