diff options
44 files changed, 1553 insertions, 566 deletions
diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile index ddfe7749..898d4a09 100644 --- a/pjmedia/build/Makefile +++ b/pjmedia/build/Makefile @@ -92,12 +92,13 @@ SPEEX_OBJS := speex_codec.o \ speex/bits.o speex/cb_search.o speex/exc_10_16_table.o \ speex/exc_10_32_table.o speex/exc_20_32_table.o \ speex/exc_5_256_table.o speex/exc_5_64_table.o \ - speex/exc_8_128_table.o speex/filters.o \ + speex/exc_8_128_table.o speex/fftwrap.c speex/filters.o \ speex/gain_table.o speex/gain_table_lbr.o \ speex/hexc_10_32_table.o speex/hexc_table.o \ - speex/high_lsp_tables.o speex/lpc_spx.o \ + speex/high_lsp_tables.o speex/jitter.c \ + speex/kiss_fft.c speex/kiss_fftr.c speex/lpc_spx.o \ speex/lsp.o speex/lsp_tables_nb.o speex/ltp.o \ - speex/math_approx.o speex/misc.o speex/modes.o \ + speex/math_approx.o speex/misc.o speex/mdf.c speex/modes.o \ speex/nb_celp.o speex/preprocess_spx.o \ speex/quant_lsp.o speex/sb_celp.o speex/smallft.o \ speex/speex.o speex/speex_callbacks.o speex/speex_header.o \ diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp index a6050c1b..3d807948 100644 --- a/pjmedia/build/pjmedia.dsp +++ b/pjmedia/build/pjmedia.dsp @@ -311,6 +311,10 @@ SOURCE=..\include\pjmedia\stream.h # End Source File
# Begin Source File
+SOURCE=..\include\pjmedia\transport.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\pjmedia\transport_udp.h
# End Source File
# Begin Source File
diff --git a/pjmedia/build/pjmedia_codec.dsp b/pjmedia/build/pjmedia_codec.dsp index ec662794..e821c493 100644 --- a/pjmedia/build/pjmedia_codec.dsp +++ b/pjmedia/build/pjmedia_codec.dsp @@ -226,6 +226,10 @@ SOURCE="..\src\pjmedia-codec\gsm\unproto.h" # PROP Default_Filter "" # Begin Source File +SOURCE="..\src\pjmedia-codec\speex\_kiss_fft_guts.h" +# End Source File +# Begin Source File + SOURCE="..\src\pjmedia-codec\speex\arch.h" # End Source File # Begin Source File @@ -250,6 +254,10 @@ SOURCE="..\src\pjmedia-codec\speex\config.h" # End Source File # Begin Source File +SOURCE="..\src\pjmedia-codec\speex\fftwrap.h" +# End Source File +# Begin Source File + SOURCE="..\src\pjmedia-codec\speex\filters.h" # End Source File # Begin Source File @@ -286,6 +294,14 @@ SOURCE="..\src\pjmedia-codec\speex\fixed_generic.h" # End Source File # Begin Source File +SOURCE="..\src\pjmedia-codec\speex\kiss_fft.h" +# End Source File +# Begin Source File + +SOURCE="..\src\pjmedia-codec\speex\kiss_fftr.h" +# End Source File +# Begin Source File + SOURCE="..\src\pjmedia-codec\speex\lpc.h" # End Source File # Begin Source File @@ -454,6 +470,10 @@ SOURCE="..\src\pjmedia-codec\speex\exc_8_128_table.c" # End Source File # Begin Source File +SOURCE="..\src\pjmedia-codec\speex\fftwrap.c" +# End Source File +# Begin Source File + SOURCE="..\src\pjmedia-codec\speex\filters.c" # ADD CPP /W4 # End Source File @@ -484,6 +504,18 @@ SOURCE="..\src\pjmedia-codec\speex\high_lsp_tables.c" # End Source File # Begin Source File +SOURCE="..\src\pjmedia-codec\speex\jitter.c" +# End Source File +# Begin Source File + +SOURCE="..\src\pjmedia-codec\speex\kiss_fft.c" +# End Source File +# Begin Source File + +SOURCE="..\src\pjmedia-codec\speex\kiss_fftr.c" +# End Source File +# Begin Source File + SOURCE="..\src\pjmedia-codec\speex\lpc_spx.c" # ADD CPP /W4 # End Source File @@ -509,6 +541,10 @@ SOURCE="..\src\pjmedia-codec\speex\math_approx.c" # End Source File # Begin Source File +SOURCE="..\src\pjmedia-codec\speex\mdf.c" +# End Source File +# Begin Source File + SOURCE="..\src\pjmedia-codec\speex\misc.c" # ADD CPP /W4 # End Source File diff --git a/pjmedia/docs/doxygen.cfg b/pjmedia/docs/doxygen.cfg index 9e8e36d1..1a466a43 100644 --- a/pjmedia/docs/doxygen.cfg +++ b/pjmedia/docs/doxygen.cfg @@ -17,7 +17,7 @@ # The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
-PROJECT_NAME = PJMEDIA
+PROJECT_NAME = "PJMEDIA and PJMEDIA-CODEC"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
@@ -107,7 +107,7 @@ BRIEF_MEMBER_DESC = YES # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
-REPEAT_BRIEF = YES
+REPEAT_BRIEF = NO
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# Doxygen will generate a detailed section even if there is only a brief
@@ -133,7 +133,7 @@ FULL_PATH_NAMES = NO # only done if one of the specified strings matches the left-hand part of
# the path. It is allowed to use relative paths in the argument list.
-STRIP_FROM_PATH = "c:\project\pjproject"
+STRIP_FROM_PATH = "/c/project/pjproject/pjmedia"
# The INTERNAL_DOCS tag determines if documentation
# that is typed after a \internal command is included. If the tag is set
@@ -154,7 +154,7 @@ CASE_SENSE_NAMES = YES # (but less readable) file names. This can be useful is your file systems
# doesn't support long names like on DOS, Mac, or CD-ROM.
-SHORT_NAMES = YES
+SHORT_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
# will show members with their full class and namespace scopes in the
@@ -166,7 +166,7 @@ HIDE_SCOPE_NAMES = NO # will generate a verbatim copy of the header file for each class for
# which an include is specified. Set to NO to disable this.
-VERBATIM_HEADERS = YES
+VERBATIM_HEADERS = NO
# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
# will put list of the files that are included by a file in the documentation
@@ -345,7 +345,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = include/pjmedia
+INPUT = include
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -403,7 +403,7 @@ EXAMPLE_RECURSIVE = NO # directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH =
+IMAGE_PATH = docs
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -494,7 +494,7 @@ HTML_OUTPUT = html # each generated HTML page (for example: .htm,.php,.asp). If it is left blank
# doxygen will generate files with .html extension.
-HTML_FILE_EXTENSION = .html
+HTML_FILE_EXTENSION = .htm
# The HTML_HEADER tag can be used to specify a personal HTML header for
# each generated HTML page. If it is left blank doxygen will generate a
@@ -568,7 +568,7 @@ DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20])
# that doxygen will group on one line in the generated HTML documentation.
-ENUM_VALUES_PER_LINE = 4
+ENUM_VALUES_PER_LINE = 1
# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
# generated containing a tree-like index structure (just like the one that
@@ -842,7 +842,8 @@ INCLUDE_FILE_PATTERNS = # omitted =1 is assumed.
PREDEFINED = PJ_DECL(x)=x PJ_DEF(x)=x PJ_IDECL(x)=x \
- PJ_IDEF(x)=x PJ_INLINE(x)=x
+ PJ_IDEF(x)=x PJ_INLINE(x)=x \
+ PJ_BEGIN_DECL= PJ_END_DECL=
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
diff --git a/pjmedia/docs/footer.html b/pjmedia/docs/footer.html index 6c0c4f05..86510676 100644 --- a/pjmedia/docs/footer.html +++ b/pjmedia/docs/footer.html @@ -1,9 +1,3 @@ -</TD></TR> -</TABLE> - -</td> -</tr> -</table> - + <!--#include virtual="/footer.html" --> </BODY> </HTML> diff --git a/pjmedia/docs/header.html b/pjmedia/docs/header.html index f8d84e3d..fdafc676 100644 --- a/pjmedia/docs/header.html +++ b/pjmedia/docs/header.html @@ -1,32 +1,7 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"> -<title>PJMEDIA Documentation</title> -<link href="doxygen.css" rel="stylesheet" type="text/css"> +<title>PJMEDIA - Open Source media stack with RTP, RTCP, SDP, conference bridge, PLC, VAD, etc.</title> +<link href="/style/style.css" rel="stylesheet" type="text/css"> </head><body> - -<TABLE id="MainTable" cellSpacing="0" cellPadding="0" width="100%" border="0"> -<!-- First Row, PJPROJECT logo. --> -<TR> - <TD> - <TABLE id="LogoTable" cellSpacing="0" cellPadding="0" width="100%" border="0"> - <TR> - <TD><a href="/" target="_top"><IMG src="/images/pjlogo.jpg" border="0"></a></TD> - <TD> </TD> - <TD> </TD> - </TR> - </TABLE> - </TD> -</TR> -<!-- Second Row, a HR. --> -<TR> - <td colspan="3"><hr noshade size="1"> - </td> -</TR> -<!-- Third row, main contents. --> -<TR> - <TD> - -<!-- Main doxygen content --> -<TABLE border="0"> - <TR><TD width="800" align="left"> + <!--#include virtual="/header.html" --> diff --git a/pjmedia/docs/master-port.jpg b/pjmedia/docs/master-port.jpg Binary files differnew file mode 100644 index 00000000..83238b4a --- /dev/null +++ b/pjmedia/docs/master-port.jpg diff --git a/pjmedia/docs/sample-manual-resampling.jpg b/pjmedia/docs/sample-manual-resampling.jpg Binary files differnew file mode 100644 index 00000000..a25b3349 --- /dev/null +++ b/pjmedia/docs/sample-manual-resampling.jpg diff --git a/pjmedia/include/pjmedia-codec/gsm.h b/pjmedia/include/pjmedia-codec/gsm.h index abcc9fbb..04f526ad 100644 --- a/pjmedia/include/pjmedia-codec/gsm.h +++ b/pjmedia/include/pjmedia-codec/gsm.h @@ -19,8 +19,22 @@ #ifndef __PJMEDIA_CODEC_GSM_H__ #define __PJMEDIA_CODEC_GSM_H__ +/** + * @file pjmedia-codec/gsm.h + * @brief GSM 06.10 codec. + */ + #include <pjmedia-codec/types.h> +/** + * @defgroup PJMED_GSM GSM 06.10 + * @ingroup PJMEDIA_CODEC + * @brief Implementation of GSM FR based on GSM 06.10 library + * @{ + * This section describes functions to register and register GSM codec + * factory to the codec manager. After the codec factory has been registered, + * application can use @ref PJMEDIA_CODEC API to manipulate the codec. + */ PJ_BEGIN_DECL @@ -48,5 +62,9 @@ PJ_DECL(pj_status_t) pjmedia_codec_gsm_deinit(void); PJ_END_DECL +/** + * @} + */ + #endif /* __PJMEDIA_CODEC_GSM_H__ */ diff --git a/pjmedia/include/pjmedia-codec/l16.h b/pjmedia/include/pjmedia-codec/l16.h index be2bf26a..225c0929 100644 --- a/pjmedia/include/pjmedia-codec/l16.h +++ b/pjmedia/include/pjmedia-codec/l16.h @@ -22,6 +22,20 @@ #include <pjmedia-codec/types.h> +/** + * @defgroup PJMED_L16 L16 Family + * @ingroup PJMEDIA_CODEC + * @brief 16bit linear codecs (useful for debugging) + * @{ + * This section describes functions to register and register L16 codec + * factory to the codec manager. After the codec factory has been registered, + * application can use @ref PJMEDIA_CODEC API to manipulate the codec. + * + * Note that the L16 codec factory registers several (about fourteen!) + * L16 codec types to codec manager (different combinations of clock + * rate and number of channels). + */ + PJ_BEGIN_DECL diff --git a/pjmedia/include/pjmedia-codec/speex.h b/pjmedia/include/pjmedia-codec/speex.h index a6e76808..a773b39e 100644 --- a/pjmedia/include/pjmedia-codec/speex.h +++ b/pjmedia/include/pjmedia-codec/speex.h @@ -19,8 +19,27 @@ #ifndef __PJMEDIA_CODEC_SPEEX_H__ #define __PJMEDIA_CODEC_SPEEX_H__ +/** + * @file speex.h + * @brief Speex codec header. + */ + #include <pjmedia-codec/types.h> +/** + * @defgroup PJMED_SPEEX Speex + * @ingroup PJMEDIA_CODEC + * @brief Implementation of Speex codecs (narrow/wide/ultrawide-band). + * @{ + * This section describes functions to register and register speex codec + * factory to the codec manager. After the codec factory has been registered, + * application can use @ref PJMEDIA_CODEC API to manipulate the codec. + * + * By default, the speex codec factory registers three Speex codecs: + * "speex/8000" narrowband codec, "speex/16000" wideband codec, and + * "speex/32000" ultra-wideband codec. This behavior can be changed by + * specifying #pjmedia_speex_options flags during initialization. + */ PJ_BEGIN_DECL @@ -59,11 +78,6 @@ PJ_DECL(pj_status_t) pjmedia_codec_speex_init( pjmedia_endpt *endpt, * pjmedia endpoint. * * @param endpt The pjmedia endpoint. - * @param options Bitmask of pjmedia_speex_options (default=0). - * @param quality Specify encoding quality, or use -1 for default - * (default=8). - * @param complexity Specify encoding complexity , or use -1 for default - * (default=8). * * @return PJ_SUCCESS on success. */ @@ -82,6 +96,9 @@ PJ_DECL(pj_status_t) pjmedia_codec_speex_deinit(void); PJ_END_DECL +/** + * @} + */ #endif /* __PJMEDIA_CODEC_SPEEX_H__ */ diff --git a/pjmedia/include/pjmedia.h b/pjmedia/include/pjmedia.h index 9e363769..3df67340 100644 --- a/pjmedia/include/pjmedia.h +++ b/pjmedia/include/pjmedia.h @@ -43,6 +43,7 @@ #include <pjmedia/sdp_neg.h> #include <pjmedia/silencedet.h> #include <pjmedia/session.h> +#include <pjmedia/transport.h> #include <pjmedia/transport_udp.h> #include <pjmedia/sound.h> #include <pjmedia/sound_port.h> diff --git a/pjmedia/include/pjmedia/clock.h b/pjmedia/include/pjmedia/clock.h index fa15ee6f..36aeb3b3 100644 --- a/pjmedia/include/pjmedia/clock.h +++ b/pjmedia/include/pjmedia/clock.h @@ -26,6 +26,23 @@ #include <pjmedia/types.h> +/** + * @addtogroup PJMEDIA_CLOCK Clock Generator + * @ingroup PJMEDIA_PORT_CLOCK + * @brief Interface for generating clock. + * @{ + * + * The clock generator provides the application with media timing, + * and it is used by the @ref PJMEDIA_MASTER_PORT for its sound clock. + * + * The clock generator may be configured to run <b>asynchronously</b> + * (the default behavior) or <b>synchronously</b>. When it is run + * asynchronously, it will call the application's callback every time + * the clock <b>tick</b> expires. When it is run synchronously, + * application must continuously polls the clock generator to synchronize + * the timing. + */ + PJ_BEGIN_DECL @@ -35,11 +52,20 @@ PJ_BEGIN_DECL typedef struct pjmedia_clock pjmedia_clock; +/** + * Options when creating the clock. + */ enum pjmedia_clock_options { + /** + * Prevents the clock from running asynchronously. In this case, + * application must poll the clock continuously by calling + * #pjmedia_clock_wait() in order to synchronize timing. + */ PJMEDIA_CLOCK_NO_ASYNC = 1, }; + /** * Type of media clock callback. * @@ -137,6 +163,9 @@ PJ_DECL(pj_status_t) pjmedia_clock_destroy(pjmedia_clock *clock); PJ_END_DECL +/** + * @} + */ #endif /* __PJMEDIA_CLOCK_H__ */ diff --git a/pjmedia/include/pjmedia/codec.h b/pjmedia/include/pjmedia/codec.h index 5b1cf9df..5f5aab89 100644 --- a/pjmedia/include/pjmedia/codec.h +++ b/pjmedia/include/pjmedia/codec.h @@ -32,24 +32,165 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_CODEC Codec framework. + * @defgroup PJMEDIA_CODEC Codec Framework * @ingroup PJMEDIA + * @brief Media codec framework and management * @{ * - * The codec manager is used to manage all codec capabilities in the endpoint. - * Library implementors can extend PJMEDIA codec capabilities by creating - * a codec factory for a new codec, and register the codec factory to - * codec manager so that the codec can be used by the rest of application. + * @section codec_mgmt_sec Codec Management + * @subsection codec_fact_sec Codec Manager * + * The codec manager is used to manage all codec capabilities in the endpoint. * When used with media endpoint (pjmedia_endpt), application can retrieve * the codec manager instance by calling #pjmedia_endpt_get_codec_mgr(). + * + * @subsection reg_new_codec Registering New Codec + * + * New codec types can be registered to PJMEDIA (or to be precise, to the + * codec manager) during run-time. + * To do this, application needs to initialize an instance of + * codec factory (#pjmedia_codec_factory) and registers this codec factory + * by calling #pjmedia_codec_mgr_register_factory(). + * + * For codecs implemented/supported by PJMEDIA, this process is normally + * concealed in an easy to use function such as #pjmedia_codec_g711_init(). + * + * @subsection codec_factory Codec Factory + * + * A codec factory (#pjmedia_codec_factory) is registered to codec manager, + * and it is used to create and release codec instance. + * + * The most important member of the codec factory is the "virtual" function + * table #pjmedia_codec_factory_op, where it contains, among other thing, + * pointer to functions to allocate and deallocate codec instance. + * + * @subsection codec_inst Codec Instance + * + * Application allocates codec instance by calling #pjmedia_codec_mgr_alloc_codec(). + * One codec instance (#pjmedia_codec) can be used for simultaneous encoding + * and decoding. + * + * The most important member of the codec instance is the "virtual" function + * table #pjmedia_codec_op, where it holds pointer to functions to + * encode/decode media frames. + * + * @subsection codec_ident Codec Identification + * + * A particular codec type in PJMEDIA can be uniquely identified by two + * keys: by #pjmedia_codec_info, or by #pjmedia_codec_id string. A fully + * qualified codec ID string consists of codec name, sampling rate, and + * number of channels. However, application may use only first parts of + * the tokens as long as it will make to codec ID unique. For example, "gsm" + * is a fully qualified codec name, since it will always have 8000 clock + * rate and 1 channel. Other examples of fully qualified codec ID strings + * are "pcma", "speex/8000", "speex/16000", and "L16/16000/1". A codec + * id "speex" (without clock rate) is not fully qualified, since it will + * match the narrowband, wideband, and ultrawideband Speex codec. + * + * The two keys can be converted to one another, with + * #pjmedia_codec_info_to_id() and #pjmedia_codec_mgr_find_codecs_by_id() + * functions. + * + * Codec ID string is not case sensitive. + * + * + * @section using_codec Using the Codec Framework + * @subsection init_alloc_codec Allocating Codec + * + * Application needs to allocate one codec instance for encoding and decoding + * media frames. One codec instance can be used to perform both encoding + * and decoding. + * + * Application allocates codec by calling #pjmedia_codec_mgr_alloc_codec(). + * This function takes #pjmedia_codec_info argument, which is used to locate + * the particular codec factory to be used to allocate the codec. + * + * Application can build #pjmedia_codec_info structure manually for + * the specific codec, or alternatively it may get the #pjmedia_codec_info + * from the codec ID string, by using #pjmedia_codec_mgr_find_codecs_by_id() + * function. + * + * The following snippet shows an example to allocate a codec: + * + \code + pj_str_t codec_id; + pjmedia_codec_info *codec_info; + unsigned count = 1; + pjmedia_codec *codec; + + codec_id = pj_str("pcma"); + + // Find codec info for the specified coded ID (i.e. "pcma"). + status = pjmedia_codec_mgr_find_codecs_by_id( codec_mgr, &codec_id, + &count, &codec_info, NULL); + + // Allocate the codec. + status = pjmedia_codec_mgr_alloc_codec( codec_mgr, codec_info, &codec ); + + \endcode + * + * + * @subsection opening_codec Initializing Codec + * + * Once codec is allocated, application needs to initialize the codec + * by calling <b><tt>open</tt></b> member of the codec. This function + * takes #pjmedia_codec_param as the argument, which contains the + * settings for the codec. + * + * Application shoud use #pjmedia_codec_mgr_get_default_param() function + * to initiaize #pjmedia_codec_param. The <tt>setting</tt> part of + * #pjmedia_codec_param then can be tuned to suit the application's + * requirements. + * + * The following snippet shows an example to initialize codec: + * + \code + pjmedia_codec_param param; + + // Retrieve default codec param for the specified codec. + pjmedia_codec_mgr_get_default_param(codec_mgr, codec_info + ¶m); + + // Application may change the "settings" part of codec param, + // for example, to disable VAD + param.setting.vad = 0; + + // Open the codec using the specified settings. + codec->op->open( codec, ¶m ); + + \endcode + * + * + * @subsection enc_dec_codec Encoding and Decoding Media Frames + * + * Application encodes and decodes media frames by calling + * <tt>encode</tt> and <tt>decode</tt> member of the codec's "virtual" + * function table (#pjmedia_codec_op). + * + * @subsection plc_codec Concealing Lost Frames + * + * All codecs has Packet Lost Concealment (PLC) feature, and application + * can activate the PLC to conceal lost frames by calling <tt>recover</tt> + * member of the codec's "virtual" function table (#pjmedia_codec_op). + * + * If the codec's algorithm supports PLC, the <tt>recover</tt> function + * will use the codec's PLC. Otherwise for codecs that don't have + * intrinsic PLC, PJMEDIA will suply the PLC implementation from the + * @ref PJMED_PLC implementation. + * + * @subsection close_codec Closing and Releasing the Codec + * + * The codec must be closed by calling <tt>close</tt> member of the codec's + * operation. Then it must be released by calling + * #pjmedia_codec_mgr_dealloc_codec(). */ /** * Standard RTP static payload types, as defined by RFC 3551. * The header file <pjmedia-codec/types.h> also declares dynamic payload - * types that are supported by pjmedia-codec library. + * type numbers that are used by PJMEDIA when advertising the capability + * for example in SDP message. */ enum pjmedia_rtp_pt { @@ -88,27 +229,21 @@ enum pjmedia_rtp_pt * Identification used to search for codec factory that supports specific * codec specification. */ -struct pjmedia_codec_info +typedef struct pjmedia_codec_info { pjmedia_type type; /**< Media type. */ unsigned pt; /**< Payload type (can be dynamic). */ pj_str_t encoding_name; /**< Encoding name. */ unsigned clock_rate; /**< Sampling rate. */ unsigned channel_cnt; /**< Channel count. */ -}; - - -/** - * @see pjmedia_codec_info - */ -typedef struct pjmedia_codec_info pjmedia_codec_info; +} pjmedia_codec_info; /** * Detailed codec attributes used both to configure a codec and to query * the capability of codec factories. */ -struct pjmedia_codec_param +typedef struct pjmedia_codec_param { /** * The "info" part of codec param describes the capability of the codec, @@ -142,16 +277,12 @@ struct pjmedia_codec_param unsigned plc:1; /**< Packet loss concealment */ unsigned reserved:1; /**< Reserved, must be zero. */ } setting; -}; +} pjmedia_codec_param; -/** - * @see pjmedia_codec_param - */ -typedef struct pjmedia_codec_param pjmedia_codec_param; -/** - * @see pjmedia_codec +/* + * Forward declaration for pjmedia_codec. */ typedef struct pjmedia_codec pjmedia_codec; @@ -160,7 +291,7 @@ typedef struct pjmedia_codec pjmedia_codec; * This structure describes codec operations. Each codec MUST implement * all of these functions. */ -struct pjmedia_codec_op +typedef struct pjmedia_codec_op { /** * Initialize codec using the specified attribute. @@ -258,29 +389,24 @@ struct pjmedia_codec_op struct pjmedia_frame *output); /** - * Instruct the codec to recover a missing frame. Not all codec has - * this capability, so this function may be NULL. + * Instruct the codec to recover a missing frame. * * @param codec The codec instance. * @param out_size The length of buffer in the output frame. - * @param output The output frame. + * @param output The output frame where generated signal + * will be placed. * * @return PJ_SUCCESS on success; */ pj_status_t (*recover)(pjmedia_codec *codec, unsigned out_size, struct pjmedia_frame *output); -}; +} pjmedia_codec_op; -/** - * Codec operation. - */ -typedef struct pjmedia_codec_op pjmedia_codec_op; - -/** - * @see pjmedia_codec_factory +/* + * Forward declaration for pjmedia_codec_factory. */ typedef struct pjmedia_codec_factory pjmedia_codec_factory; @@ -309,7 +435,7 @@ struct pjmedia_codec * This structure describes operations that must be supported by codec * factories. */ -struct pjmedia_codec_factory_op +typedef struct pjmedia_codec_factory_op { /** * Check whether the factory can create codec with the specified @@ -380,14 +506,9 @@ struct pjmedia_codec_factory_op pj_status_t (*dealloc_codec)(pjmedia_codec_factory *factory, pjmedia_codec *codec ); -}; +} pjmedia_codec_factory_op; -/** - * @see pjmedia_codec_factory_op - */ -typedef struct pjmedia_codec_factory_op pjmedia_codec_factory_op; - /** * Codec factory describes a module that is able to create codec with specific @@ -418,7 +539,7 @@ struct pjmedia_codec_factory * Specify these values to set the codec priority, by calling * #pjmedia_codec_mgr_set_codec_priority(). */ -enum pjmedia_codec_priority +typedef enum pjmedia_codec_priority { /** * This priority makes the codec the highest in the order. @@ -455,16 +576,14 @@ enum pjmedia_codec_priority * query functions. */ PJMEDIA_CODEC_PRIO_DISABLED = 0, -}; - -/** - * @see pjmedia_codec_priority - */ -typedef enum pjmedia_codec_priority pjmedia_codec_priority; +} pjmedia_codec_priority; -/** Fully qualified codec name (e.g. "pcmu/8000/1") */ +/** + * Codec identification (e.g. "pcmu/8000/1"). + * See @ref codec_ident for more info. + */ typedef char pjmedia_codec_id[32]; @@ -486,7 +605,7 @@ struct pjmedia_codec_desc * to see this declaration, but nevertheless this declaration is needed * by media endpoint to instantiate the codec manager. */ -struct pjmedia_codec_mgr +typedef struct pjmedia_codec_mgr { /** List of codec factories registered to codec manager. */ pjmedia_codec_factory factory_list; @@ -496,13 +615,8 @@ struct pjmedia_codec_mgr /** Array of codec descriptor. */ struct pjmedia_codec_desc codec_desc[PJMEDIA_CODEC_MGR_MAX_CODECS]; -}; - -/** - * @see pjmedia_codec_mgr - */ -typedef struct pjmedia_codec_mgr pjmedia_codec_mgr; +} pjmedia_codec_mgr; diff --git a/pjmedia/include/pjmedia/conference.h b/pjmedia/include/pjmedia/conference.h index 7346f7c1..9cb7c861 100644 --- a/pjmedia/include/pjmedia/conference.h +++ b/pjmedia/include/pjmedia/conference.h @@ -26,6 +26,12 @@ */ #include <pjmedia/port.h> +/** + * @defgroup PJMEDIA_CONF Conference Bridge + * @ingroup PJMEDIA_PORT + * @brief The implementation of conference bridge + * @{ + */ PJ_BEGIN_DECL @@ -236,7 +242,7 @@ PJ_DECL(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf, * @param src_slot Source slot. * @param sink_slot Sink slot. * - * @reutrn PJ_SUCCESS on success. + * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf, unsigned src_slot, @@ -373,5 +379,10 @@ PJ_DECL(pj_status_t) pjmedia_conf_adjust_tx_level( pjmedia_conf *conf, PJ_END_DECL +/** + * @} + */ + + #endif /* __PJMEDIA_CONF_H__ */ diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h index 89bbd4e8..4533c0f4 100644 --- a/pjmedia/include/pjmedia/config.h +++ b/pjmedia/include/pjmedia/config.h @@ -19,13 +19,35 @@ #ifndef __PJMEDIA_CONFIG_H__ #define __PJMEDIA_CONFIG_H__ +/** + * @file pjmedia/config.h Compile time config + * @brief Contains some compile time constants. + */ #include <pj/config.h> +/** + * @defgroup PJMEDIA_BASE Base Types and Configurations + * @ingroup PJMEDIA + */ + +/** + * @defgroup PJMEDIA_CONFIG Compile time configuration + * @ingroup PJMEDIA_BASE + * @brief Some compile time configuration settings. + * @{ + */ + /* * Types of sound stream backends. */ + +/** Constant for NULL sound backend. */ #define PJMEDIA_SOUND_NULL_SOUND 0 + +/** Constant for PortAudio sound backend. */ #define PJMEDIA_SOUND_PORTAUDIO_SOUND 1 + +/** Constant for Win32 DirectSound sound backend. */ #define PJMEDIA_SOUND_WIN32_DIRECT_SOUND 2 @@ -132,6 +154,10 @@ #endif +/** + * @} + */ + #endif /* __PJMEDIA_CONFIG_H__ */ diff --git a/pjmedia/include/pjmedia/doxygen.h b/pjmedia/include/pjmedia/doxygen.h index e251cef2..9ebd27e6 100644 --- a/pjmedia/include/pjmedia/doxygen.h +++ b/pjmedia/include/pjmedia/doxygen.h @@ -34,71 +34,295 @@ */ /** - * @mainpage Welcome to PJMEDIA! + * @mainpage PJMEDIA and PJMEDIA-CODEC * - * @section intro_sec What is PJMEDIA + * \n + * @section intro_sec PJMEDIA * - * PJMEDIA open source (GPL) library contains objects that implements multimedia - * capabilities. It can be used with signaling libraries such as PJSIP to create - * a complete multimedia communication endpoint. + * PJMEDIA is a rather complete media stack, distributed under Open Source/GPL + * terms, and featuring small footprint and good extensibility and portability. * + * Please click the <A HREF="modules.htm"><b>Modules</b></A> link on top + * of this page to get the complete features currently present in PJMEDIA. * - * @subsection pjmedia_about_subsec About PJMEDIA + * Also please read the documentation about @ref PJMEDIA_PORT_CONCEPT, + * which is a major concept that is used for implementing many objects in + * the library. * - * <pre> - * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org> + * \n + * @section pjmedia_codec_sec PJMEDIA-CODEC * - * 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. + * PJMEDIA-CODEC is a static library containing various codec implementations, + * wrapped into PJMEDIA codec framework. The static library is designed as + * such so that only codecs that are explicitly initialized are linked with + * the application, therefore keeping the application size in control. * - * 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. + * Please see @ref pjmedia_codec_page on how to use the codec in + * PJMEDIA-CODEC. * - * 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 - * </pre> + * \n + * @section pjmedia_lic Copying and Acknowledgements + * + * Please see @ref lic_stuffs page for the details. + */ + + +/** + * @page pjmedia_codec_page Using PJMEDIA-CODEC + * + * Before application can use a codec, it needs to initialize and register + * the codec to the codec manager. This is accomplished with using + * constructs like the following: + * + \code + #include <pjmedia.h> + #include <pjmedia-codec.h> + + init_codecs( pjmedia_endpt *med_ept ) + { + // Register G.711 codecs + pjmedia_codec_g711_init(med_ept); + + // Register GSM codec. + pjmedia_codec_gsm_init(med_ept); + + // Register Speex codecs. + // With the default flag, this will register three codecs: + // speex/8000, speex/16000, and speex/32000 + pjmedia_codec_speex_init(med_ept, 0, 0, 0); + } + \endcode + * + * After the codec is registered, application may create the encoder/decoder + * instance, by using the API as documented in @ref PJMEDIA_CODEC. + */ + + + +/** + * @page lic_stuffs Copying and Acknowledgements + * @section lic_stuff Copying and Acknowledgements + * @subsection pjmedia_about_subsec About PJMEDIA * + * PJMEDIA is distributed under GPL terms (other licensing schemes may be + * arranged): + \verbatim + 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 + \endverbatim * - * @subsection portaudio_subsec About PortAudio * - * PortAudio is an excellent sound device library that is chosen as sound - * device abstraction in PJMEDIA. It has the following characteristics that - * makes it perfect for our use: + * @section other_acks Acknowlegments + * @subsection portaudio_subsec PortAudio * - * - It is portable and complete - *\n - * It supports multiple back-ends on Windows, Windows CE (WinCE)/PocketPC, - * Linux, Unix, and MacOS. More platforms may be supported. - * - It is callback based - *\n - * The callback based for supplying/retrieving frames from the audio - * device is perfect for our use. - * - No nonsense, C based library. - * - Actively maintained. + * PortAudio is supported as one of the sound device backend, and + * is used by default on Linux/Unix and MacOS X target. * - * Please visit http://www.portaudio.com for more info. + * Please visit <A HREF="http://www.portaudio.com">http://www.portaudio.com</A> + * for more info. * * PortAudio is distributed with the following condition. - * <pre> - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2000 Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * </pre> + \verbatim + Based on the Open Source API proposed by Ross Bencina + Copyright (c) 1999-2000 Phil Burk + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + \endverbatim + * + * + * @subsection resample_ack Resample + * + * PJMEDIA uses <tt>resample-1.8.tar.gz</tt> from + * <A HREF="http://www-ccrma.stanford.edu/~jos/resample/"> + * Digital Audio Resampling Home Page</A>. This library is distibuted + * on LGPL terms. + * + * Some excerpts from the original source codes: + \verbatim + HISTORY + + The first version of this software was written by Julius O. Smith III + <jos@ccrma.stanford.edu> at CCRMA <http://www-ccrma.stanford.edu> in + 1981. It was called SRCONV and was written in SAIL for PDP-10 + compatible machines. The algorithm was first published in + + Smith, Julius O. and Phil Gossett. ``A Flexible Sampling-Rate + Conversion Method,'' Proceedings (2): 19.4.1-19.4.4, IEEE Conference + on Acoustics, Speech, and Signal Processing, San Diego, March 1984. + + An expanded tutorial based on this paper is available at the Digital + Audio Resampling Home Page given above. + + Circa 1988, the SRCONV program was translated from SAIL to C by + Christopher Lee Fraley working with Roger Dannenberg at CMU. + + Since then, the C version has been maintained by jos. + + Sndlib support was added 6/99 by John Gibson <jgg9c@virginia.edu>. + + The resample program is free software distributed in accordance + with the Lesser GNU Public License (LGPL). There is NO warranty; not + even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + \endverbatim + * + * @subsection jb_ack Adaptive Jitter Buffer + * + * The PJMEDIA jitter buffer is based on implementation kindly donated + * by <A HREF="http://www.switchlab.com">Switchlab, Ltd.</A>, and is + * distributed under PJMEDIA licensing terms. + * + * + * @subsection silence_det_ack Adaptive Silence Detector + * + * The adaptive silence detector was based on silence detector + * implementation in <A HREF="http://www.openh323.org">Open H323</A> + * project. I couldn't find the source code anymore, but generally + * Open H323 files are distributed under MPL terms and has the + * following excerpts: + \verbatim + Open H323 Library + + Copyright (c) 1998-2000 Equivalence Pty. Ltd. + + The contents of this file are subject to the Mozilla Public License + Version 1.0 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + The Original Code is Open H323 Library. + + The Initial Developer of the Original Code is Equivalence Pty. Ltd. + + Portions of this code were written with the assisance of funding from + Vovida Networks, Inc. http://www.vovida.com. + \endverbatim + + * @subsection gsm_ack GSM Codec + * + * PJMEDIA uses GSM + * <A HREF="http://kbs.cs.tu-berlin.de/~jutta/toast.html">GSM 06.10</A> + * version 1.0 at patchlevel 12. It has the following Copyright notice: + * + \verbatim + Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, + Technische Universitaet Berlin + + Any use of this software is permitted provided that this notice is not + removed and that neither the authors nor the Technische Universitaet Berlin + are deemed to have made any representations as to the suitability of this + software for any purpose nor are held responsible for any defects of + this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + + As a matter of courtesy, the authors request to be informed about uses + this software has found, about bugs in this software, and about any + improvements that may be of general interest. + + Berlin, 28.11.1994 + Jutta Degener + Carsten Bormann + \endverbatim + * + * + * @subsection speex_codec_ack Speex Codec + * + * PJMEDIA uses Speex codec uses version 1.1.12 from <A HREF="http://www.speex.org"> + * www.speex.org</A>. The Speex library comes with the following Copying + * notice: + \verbatim + Copyright 2002-2005 + Xiph.org Foundation + Jean-Marc Valin + David Rowe + EpicGames + Analog Devices + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + \endverbatim + * + * + * @subsection g711_codec_ack G.711 Codec + * + * The G.711 codec algorithm came from Sun Microsystems, Inc, and it's + * got the following excerpts: + * + \verbatim + This source code is a product of Sun Microsystems, Inc. and is provided + for unrestricted use. Users may copy or modify this source code without + charge. + + SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + + Sun source code is provided with no support and without any obligation on + the part of Sun Microsystems, Inc. to assist in its use, correction, + modification or enhancement. + + SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + OR ANY PART THEREOF. + + In no event will Sun Microsystems, Inc. be liable for any lost revenue + or profits or other special, indirect and consequential damages, even if + Sun has been advised of the possibility of such damages. + + Sun Microsystems, Inc. + 2550 Garcia Avenue + Mountain View, California 94043 + \endverbatim + * */ #endif /* __PJMEDIA_DOXYGEN_H__ */ diff --git a/pjmedia/include/pjmedia/endpoint.h b/pjmedia/include/pjmedia/endpoint.h index f90915fa..38a05f81 100644 --- a/pjmedia/include/pjmedia/endpoint.h +++ b/pjmedia/include/pjmedia/endpoint.h @@ -25,7 +25,7 @@ * @brief Media endpoint. */ /** - * @defgroup PJMED_ENDPT Multimedia Endpoint + * @defgroup PJMED_ENDPT The Endpoint * @ingroup PJMEDIA * @{ * diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h index 7909b557..a78ed131 100644 --- a/pjmedia/include/pjmedia/errno.h +++ b/pjmedia/include/pjmedia/errno.h @@ -19,9 +19,22 @@ #ifndef __PJMEDIA_ERRNO_H__ #define __PJMEDIA_ERRNO_H__ +/** + * @file errno.h Error Codes + * @brief PJMEDIA specific error codes. + */ + #include <pjmedia/types.h> #include <pj/errno.h> +/** + * @defgroup PJMEDIA_ERRNO Error Codes + * @ingroup PJMEDIA_BASE + * @brief PJMEDIA specific error codes. + * @{ + */ + + PJ_BEGIN_DECL @@ -31,12 +44,12 @@ PJ_BEGIN_DECL #define PJMEDIA_ERRNO_START (PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) -/* +/** * Mapping from PortAudio error codes to pjmedia error space. */ #define PJMEDIA_PORTAUDIO_ERRNO_START (PJMEDIA_ERRNO_START+PJ_ERRNO_SPACE_SIZE-1000) -/* +/** * Convert PortAudio error code to PJMEDIA error code. */ #define PJMEDIA_ERRNO_FROM_PORTAUDIO(err) (err+PJMEDIA_PORTAUDIO_ERRNO_START) @@ -389,11 +402,6 @@ PJ_BEGIN_DECL /************************************************************ - * JITTER BUFFER ERRORS - ***********************************************************/ - - -/************************************************************ * PORT ERRORS ***********************************************************/ /** @@ -486,5 +494,10 @@ PJ_BEGIN_DECL PJ_END_DECL +/** + * @} + */ + + #endif /* __PJMEDIA_ERRNO_H__ */ diff --git a/pjmedia/include/pjmedia/g711.h b/pjmedia/include/pjmedia/g711.h index f3a3d0c7..c3ef5f2c 100644 --- a/pjmedia/include/pjmedia/g711.h +++ b/pjmedia/include/pjmedia/g711.h @@ -19,8 +19,22 @@ #ifndef __PJMEDIA_G711_H__ #define __PJMEDIA_G711_H__ +/** + * @file g711.h + * @brief G711 Codec + */ + #include <pjmedia-codec/types.h> +/** + * @defgroup PJMED_G711 G711 + * @ingroup PJMEDIA_CODEC + * @brief Standard G.711/PCMA and PCMU codec. + * @{ + * This section describes functions to register and register G.711 codec + * factory to the codec manager. After the codec factory has been registered, + * application can use @ref PJMEDIA_CODEC API to manipulate the codec. + */ PJ_BEGIN_DECL @@ -47,6 +61,9 @@ PJ_DECL(pj_status_t) pjmedia_codec_g711_deinit(void); PJ_END_DECL +/** + * @} + */ #endif /* __PJMEDIA_G711_H__ */ diff --git a/pjmedia/include/pjmedia/jbuf.h b/pjmedia/include/pjmedia/jbuf.h index 013f61aa..301ab77e 100644 --- a/pjmedia/include/pjmedia/jbuf.h +++ b/pjmedia/include/pjmedia/jbuf.h @@ -31,9 +31,15 @@ /** * @defgroup PJMED_JBUF Adaptive jitter buffer - * @ingroup PJMEDIA + * @ingroup PJMEDIA_FRAME_OP * @{ + * This section describes PJMEDIA's implementation of de-jitter buffer. + * The de-jitter buffer may be set to operate in adaptive mode or fixed + * delay mode. * + * The jitter buffer is also able to report the status of the current + * frame (#pjmedia_jb_frame_type). This status is used for examply by + * @ref PJMED_STRM to invoke the codec's @ref PJMED_PLC algorithm. */ diff --git a/pjmedia/include/pjmedia/master_port.h b/pjmedia/include/pjmedia/master_port.h index 06af20b3..ccc1bedd 100644 --- a/pjmedia/include/pjmedia/master_port.h +++ b/pjmedia/include/pjmedia/master_port.h @@ -26,22 +26,40 @@ */ #include <pjmedia/port.h> +/** + * @defgroup PJMEDIA_MASTER_PORT Master Port + * @ingroup PJMEDIA_PORT_CLOCK + * @brief Provides media clock for media ports. + * @{ + * A master port has two media ports connected to it, and by convention + * thay are called downstream and upstream ports. The media stream flowing to + * the downstream port is called encoding or send direction, and media stream + * flowing to the upstream port is called decoding or receive direction + * (imagine the downstream as stream to remote endpoint, and upstream as + * local media port; media flowing to remote endpoint (downstream) will need + * to be encoded before it is transmitted to remote endpoint). + * + * A master port internally has an instance of @ref PJMEDIA_CLOCK, which + * provides the essensial timing for the master port. The @ref PJMEDIA_CLOCK + * runs asynchronously, and whenever a clock <b>tick</b> expires, a callback + * will be called, and the master port performs the following tasks: + * - it calls <b><tt>get_frame()</tt></b> from the downstream port, + * when give the frame to the upstream port by calling <b><tt>put_frame + * </tt></b> to the upstream port, and + * - performs the same task, but on the reverse direction (i.e. get the stream + * from upstream port and give it to the downstream port). + * + * Because master port enables media stream to flow automatically, it is + * said that the master port supplies @ref PJMEDIA_PORT_CLOCK to the + * media ports interconnection. + * + */ PJ_BEGIN_DECL /** * Opaque declaration for master port. - * A master port has two media ports connected to it, i.e. downstream and - * upstream ports. The media stream flowing to the downstream port is called - * encoding or send direction, and media stream flowing to the upstream port - * is called decoding or receive direction. - * - * A master port has a "clock" that periodically passes the media frame from - * downstream to upstream ports, and vice versa. In each run, it retrieves - * media frame from one side with #pjmedia_port_get_frame(), and passes the - * media frame to the other side with #pjmedia_port_put_frame(). In each run, - * this process is done for twice, i.e. one for each direction. */ typedef struct pjmedia_master_port pjmedia_master_port; @@ -149,6 +167,10 @@ PJ_DECL(pj_status_t) pjmedia_master_port_destroy(pjmedia_master_port *m, PJ_END_DECL +/** + * @} + */ + #endif /* __PJMEDIA_MASTER_PORT_H__ */ diff --git a/pjmedia/include/pjmedia/null_port.h b/pjmedia/include/pjmedia/null_port.h index 36509181..d9203602 100644 --- a/pjmedia/include/pjmedia/null_port.h +++ b/pjmedia/include/pjmedia/null_port.h @@ -26,12 +26,22 @@ #include <pjmedia/port.h> + +/** + * @defgroup PJMEDIA_NULL_PORT Null Port + * @ingroup PJMEDIA_PORT + * @brief Null port is the simplest type of port. + * @{ + */ + + PJ_BEGIN_DECL /** * Create Null port. * + * @param pool Pool to allocate memory. * @param sampling_rate Sampling rate of the port. * @param channel_count Number of channels. * @param samples_per_frame Number of samples per frame. @@ -51,5 +61,9 @@ PJ_DECL(pj_status_t) pjmedia_null_port_create( pj_pool_t *pool, PJ_END_DECL +/** + * @} + */ + #endif /* __PJMEDIA_NULL_PORT_H__ */ diff --git a/pjmedia/include/pjmedia/plc.h b/pjmedia/include/pjmedia/plc.h index e0631c73..6b80d18a 100644 --- a/pjmedia/include/pjmedia/plc.h +++ b/pjmedia/include/pjmedia/plc.h @@ -28,9 +28,18 @@ /** * @defgroup PJMED_PLC Packet Lost Concealment - * @ingroup PJMEDIA + * @ingroup PJMEDIA_FRAME_OP * @{ + * This section describes PJMEDIA's implementation of Packet Lost + * Concealment algorithm. This algorithm is used to implement PLC for + * codecs that do not have built-in support for one (e.g. G.711 or GSM codecs). * + * The PLC algorithm (either built-in or external) is embedded in + * PJMEDIA codec instance, and application can conceal lost frames + * by calling <b><tt>recover()</tt></b> member of the codec's member + * operation (#pjmedia_codec_op). + * + * See also @ref plc_codec for more info. */ diff --git a/pjmedia/include/pjmedia/port.h b/pjmedia/include/pjmedia/port.h index fbc58552..cd0dbe9a 100644 --- a/pjmedia/include/pjmedia/port.h +++ b/pjmedia/include/pjmedia/port.h @@ -27,6 +27,206 @@ #include <pj/os.h> +/** + @defgroup PJMEDIA_PORT_CONCEPT Media Ports + @ingroup PJMEDIA + @brief Extensible framework for media terminations + + @section media_port_intro Concepts + + @subsection The Media Port + A media port (represented with pjmedia_port "class") provides a generic + and extensible framework for implementing media terminations. A media + port interface basically has the following properties: + - media port information (pjmedia_port_info) to describe the + media port properties (sampling rate, number of channels, etc.), + - pointer to function to acquire frames from the port (<tt>get_frame() + </tt> interface), which will be called by #pjmedia_port_get_frame() + public API, and + - pointer to function to store frames to the port (<tt>put_frame()</tt> + interface) which will be called by #pjmedia_port_put_frame() public + API. + + Media ports are passive "objects". Applications (or other PJMEDIA + components) must actively calls #pjmedia_port_get_frame() or + #pjmedia_port_put_frame() from/to the media port in order to retrieve/ + store media frames. + + Some media ports (such as @ref PJMEDIA_CONF and @ref PJMEDIA_RESAMPLE_PORT) + may be interconnected with each other, while some + others represent the ultimate source/sink termination for the media. + The #pjmedia_port_connect() and #pjmedia_port_disconnect() are used to + connect and disconnect media ports respectively. But even when ports + are connected with each other ports, they still remain passive. + + + @subsection port_clock_ex1 Example: Manual Resampling + + For example, suppose application wants to convert the sampling rate + of one WAV file to another. In this case, application would create and + arrange media ports connection as follows: + + \image html sample-manual-resampling.jpg + + Application would setup the media ports using the following pseudo- + code: + + \code + + pjmedia_port *player, *resample, *writer; + pj_status_t status; + + // Create the file player port. + status = pjmedia_wav_player_port_create(pool, + "Input.WAV", // file name + 20, // ptime. + PJMEDIA_FILE_NO_LOOP, // flags + 0, // buffer size + NULL, // user data. + &player ); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS); + + // Create the resample port with specifying the target sampling rate, + // and with the file port as the source. This will effectively + // connect the resample port with the player port. + status = pjmedia_resample_port_create( pool, player, 8000, + 0, &resample); + PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS); + + // Create the file writer, specifying the resample port's configuration + // as the WAV parameters. + status pjmedia_wav_writer_port_create(pool, + "Output.WAV", // file name. + resample->info.clock_rate, + resample->info.channel_count, + resample->info.samples_per_frame, + resample->info.bits_per_sample, + 0, // flags + 0, // buffer size + NULL, // user data. + &writer); + + \endcode + + + After the ports have been set up, application can perform the conversion + process by running this loop: + + \code + + pj_int16_t samplebuf[MAX_FRAME]; + + while (1) { + pjmedia_frame frame; + pj_status_t status; + + frame.buf = samplebuf; + frame.size = sizeof(samplebuf); + + // Get the frame from resample port. + status = pjmedia_port_get_frame(resample, &frame); + if (status != PJ_SUCCESS || frame.type == PJMEDIA_FRAME_TYPE_NONE) { + // End-of-file, end the conversion. + break; + } + + // Put the frame to write port. + status = pjmedia_port_put_frame(writer, &frame); + if (status != PJ_SUCCESS) { + // Error in writing the file. + break; + } + } + + \endcode + + For the sake of completeness, after the resampling process is done, + application would need to destroy the ports: + + \code + // Note: by default, destroying resample port will destroy the + // the downstream port too. + pjmedia_port_destroy(resample); + pjmedia_port_destroy(writer); + \endcode + + + The above steps are okay for our simple purpose of changing file's sampling + rate. But for other purposes, the process of reading and writing frames + need to be done in timely manner (for example, sending RTP packets to + remote stream). And more over, as the application's scope goes bigger, + the same pattern of manually reading/writing frames comes up more and more often, + thus perhaps it would be better if PJMEDIA provides mechanism to + automate this process. + + And indeed PJMEDIA does provide such mechanism, which is described in + @ref PJMEDIA_PORT_CLOCK section. + + + @subsection media_port_autom Automating Media Flow + + PJMEDIA provides few mechanisms to make media flows automatically + among media ports. This concept is described in @ref PJMEDIA_PORT_CLOCK + section. + + */ + + +/** + * @defgroup PJMEDIA_PORT_INTERFACE Media Port Interface + * @ingroup PJMEDIA_PORT_CONCEPT + * @brief Declares the media port interface. + */ + +/** + * @defgroup PJMEDIA_PORT Ports + * @ingroup PJMEDIA_PORT_CONCEPT + * @brief Contains various types of media ports/terminations. + * @{ + * This page lists all types of media ports currently implemented + * in PJMEDIA. The media port concept is explained in @ref PJMEDIA_PORT_CONCEPT. + * @} + */ + +/** + @defgroup PJMEDIA_PORT_CLOCK Clock/Timing + @ingroup PJMEDIA_PORT_CONCEPT + @brief Various types of classes that provide timing. + @{ + + The media clock/timing extends the media port concept that is explained + in @ref PJMEDIA_PORT_CONCEPT. When clock is present in the ports + interconnection, media will flow automatically (and with correct timing too!) + from one media port to another. + + There are few objects in PJMEDIA that are able to provide clock/timing + to media ports interconnection: + + - @ref PJMED_SND_PORT\n + The sound device makes a good candidate as the clock source, and + PJMEDIA @ref PJMED_SND is designed so that it is able to invoke + operations according to timing driven by the sound hardware clock + (this may sound complicated, but actually it just means that + the sound device abstraction provides callbacks to be called when + it has/wants media frames).\n + See @ref PJMED_SND_PORT for more details. + + - @ref PJMEDIA_MASTER_PORT\n + The master port uses @ref PJMEDIA_CLOCK as the clock source. By using + @ref PJMEDIA_MASTER_PORT, it is possible to interconnect passive + media ports and let the frames flow automatically in timely manner.\n + Please see @ref PJMEDIA_MASTER_PORT for more details. + + @} + */ + +/** + * @addtogroup PJMEDIA_PORT_INTERFACE + * @{ + * This page contains the media port interface declarations. The media port + * concept is explained in @ref PJMEDIA_PORT_CONCEPT. + */ + PJ_BEGIN_DECL @@ -68,7 +268,7 @@ typedef enum pjmedia_port_op pjmedia_port_op; /** * Port info. */ -struct pjmedia_port_info +typedef struct pjmedia_port_info { pj_str_t name; /**< Port name. */ pj_uint32_t signature; /**< Port signature. */ @@ -82,30 +282,19 @@ struct pjmedia_port_info unsigned bits_per_sample; /**< Bits/sample */ unsigned samples_per_frame; /**< No of samples per frame. */ unsigned bytes_per_frame; /**< No of samples per frame. */ -}; - -/** - * @see pjmedia_port_info - */ -typedef struct pjmedia_port_info pjmedia_port_info; +} pjmedia_port_info; /** * Types of media frame. */ -enum pjmedia_frame_type +typedef enum pjmedia_frame_type { PJMEDIA_FRAME_TYPE_NONE, /**< No frame. */ PJMEDIA_FRAME_TYPE_CNG, /**< Silence audio frame. */ PJMEDIA_FRAME_TYPE_AUDIO, /**< Normal audio frame. */ -}; - - -/** - * @see pjmedia_frame_type - */ -typedef enum pjmedia_frame_type pjmedia_frame_type; +} pjmedia_frame_type; /** @@ -142,25 +331,8 @@ typedef struct pjmedia_port pjmedia_port; */ struct pjmedia_port { - pjmedia_port_info info; - pjmedia_graph *graph; - pjmedia_port *upstream_port; - pjmedia_port *downstream_port; - void *user_data; - - /** - * Called when this port is connected to an upstream port. - */ - pj_status_t (*on_upstream_connect)(pj_pool_t *pool, - pjmedia_port *this_port, - pjmedia_port *upstream); - - /** - * Called when this port is connected to a downstream port. - */ - pj_status_t (*on_downstream_connect)(pj_pool_t *pool, - pjmedia_port *this_port, - pjmedia_port *upstream); + pjmedia_port_info info; /**< Port information. */ + void *user_data; /**< User data. */ /** * Sink interface. @@ -183,21 +355,6 @@ struct pjmedia_port }; - -/** - * Connect two ports. - */ -PJ_DECL(pj_status_t) pjmedia_port_connect( pj_pool_t *pool, - pjmedia_port *upstream_port, - pjmedia_port *downstream_port); - -/** - * Disconnect ports. - */ -PJ_DECL(pj_status_t) pjmedia_port_disconnect( pjmedia_port *upstream_port, - pjmedia_port *downstream_port); - - /** * Get a frame from the port (and subsequent downstream ports). */ @@ -220,6 +377,9 @@ PJ_DECL(pj_status_t) pjmedia_port_destroy( pjmedia_port *port ); PJ_END_DECL +/** + * @} + */ #endif /* __PJMEDIA_PORT_H__ */ diff --git a/pjmedia/include/pjmedia/resample.h b/pjmedia/include/pjmedia/resample.h index 1def54ce..ae129f1f 100644 --- a/pjmedia/include/pjmedia/resample.h +++ b/pjmedia/include/pjmedia/resample.h @@ -22,12 +22,21 @@ /** - * @file reample.h + * @file resample.h * @brief Sample rate converter. */ #include <pjmedia/types.h> #include <pjmedia/port.h> +/** + * @defgroup PJMEDIA_RESAMPLE Resampling Algorithm + * @ingroup PJMEDIA_FRAME_OP + * @brief Functions to alter frame's clock rate. + * @{ + * This section describes the base resampling functions. In addition to this, + * application can use the @ref PJMEDIA_RESAMPLE_PORT which provides + * media port abstraction for the base resampling algorithm. + */ PJ_BEGIN_DECL @@ -98,45 +107,82 @@ PJ_DECL(unsigned) pjmedia_resample_get_input_size(pjmedia_resample *resample); /** + * @} + */ + +/** + * @defgroup PJMEDIA_RESAMPLE_PORT Resample Port + * @ingroup PJMEDIA_PORT + * @brief Media port interface to change media stream's sampling rate. + * @{ + * This section describes media port abstractoin for @ref PJMEDIA_RESAMPLE. + */ + + +/** + * Option flags that can be specified when creating resample port. + */ +enum pjmedia_resample_port_options +{ + /** + * Do not use high quality resampling algorithm, but use linear + * algorithm instead. + */ + PJMEDIA_RESAMPLE_USE_LINEAR = 1, + + /** + * Use small filter workspace when high quality resampling is + * used. + */ + PJMEDIA_RESAMPLE_USE_SMALL_FILTER = 2, + + /** + * Do not destroy downstream port when resample port is destroyed. + */ + PJMEDIA_RESAMPLE_DONT_DESTROY_DN = 4, +}; + + + +/** * Create a resample port. This creates a bidirectional resample session, * which will resample frames when the port's get_frame() and put_frame() * is called. * * When the resample port's get_frame() is called, this port will get - * a frame from the downstream port and resample the frame to the upstream - * port's clock rate before returning it to the caller. + * a frame from the downstream port and resample the frame to the target + * clock rate before returning it to the caller. * * When the resample port's put_frame() is called, this port will resample - * the frame to the downstream's port clock rate before giving the frame + * the frame to the downstream port's clock rate before giving the frame * to the downstream port. * * @param pool Pool to allocate the structure and buffers. - * @param high_quality If true, then high quality conversion will be - * used, at the expense of more CPU and memory, - * because temporary buffer needs to be created. - * @param large_filter If true, large filter size will be used. - * @param downstream_rate The sampling rate of the downstream port. - * @param upstream_rate The sampling rate of the upstream port. - * @param channel_count The number of channels. This argument is only - * used for the port information. It does not - * change the behavior of the resample port. - * @param samples_per_frame Number of samples per frame from the downstream - * port. + * @param dn_port The downstream port, which clock rate is to + * be converted to the target clock rate. + * @param clock_rate Target clock rate. + * @param options Flags from #pjmedia_resample_port_options. + * When this flag is zero, the default behavior + * is to use high quality resampling with + * large filter, and to destroy downstream port + * when resample port is destroyed. * @param p_port Pointer to receive the resample port instance. * * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool, - pj_bool_t high_quality, - pj_bool_t large_filter, - unsigned downstream_rate, - unsigned upstream_rate, - unsigned channel_count, - unsigned samples_per_frame, + pjmedia_port *dn_port, + unsigned clock_rate, + unsigned options, pjmedia_port **p_port ); PJ_END_DECL +/** + * @} + */ + + #endif /* __PJMEDIA_RESAMPLE_H__ */ diff --git a/pjmedia/include/pjmedia/rtcp.h b/pjmedia/include/pjmedia/rtcp.h index 482d487c..60ad19f1 100644 --- a/pjmedia/include/pjmedia/rtcp.h +++ b/pjmedia/include/pjmedia/rtcp.h @@ -32,8 +32,8 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_RTCP RTCP Management - * @ingroup PJMEDIA + * @defgroup PJMED_RTCP RTCP Session + * @ingroup PJMEDIA_TRANSPORT * @{ */ @@ -218,6 +218,10 @@ struct pjmedia_rtcp_stat typedef struct pjmedia_rtcp_stat pjmedia_rtcp_stat; +/** + * The types for keeping the average jitter value. Ideally a floating point + * number should be used, but this is not always available/desired. + */ #if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0 typedef double PJMEDIA_AVG_JITTER_TYPE; #else diff --git a/pjmedia/include/pjmedia/rtp.h b/pjmedia/include/pjmedia/rtp.h index 29dad419..edad178a 100644 --- a/pjmedia/include/pjmedia/rtp.h +++ b/pjmedia/include/pjmedia/rtp.h @@ -31,15 +31,16 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_RTP RTP Packet and RTP Session Management - * @ingroup PJMEDIA + * @defgroup PJMED_RTP RTP Session + * @ingroup PJMEDIA_TRANSPORT * @{ * * The RTP module is designed to be dependent only to PJLIB, it does not depend * on any other parts of PJMEDIA library. The RTP module does not even depend * on any transports (sockets), to promote even more use. * - * An RTCP implementation is available, in separate module. + * An RTCP implementation is available, in separate module. Please see + * @ref PJMED_RTCP. * * The functions that are provided by this module: * - creating RTP header for each outgoing packet. @@ -129,9 +130,9 @@ typedef struct pjmedia_rtp_ext_hdr pjmedia_rtp_ext_hdr; */ struct pjmedia_rtp_dtmf_event { - pj_uint8_t event; - pj_uint8_t e_vol; - pj_uint16_t duration; + pj_uint8_t event; /**< Event type ID. */ + pj_uint8_t e_vol; /**< Event volume. */ + pj_uint16_t duration; /**< Event duration. */ }; /** diff --git a/pjmedia/include/pjmedia/sdp.h b/pjmedia/include/pjmedia/sdp.h index e4d9ddf5..2bc43bb2 100644 --- a/pjmedia/include/pjmedia/sdp.h +++ b/pjmedia/include/pjmedia/sdp.h @@ -27,8 +27,8 @@ /** - * @defgroup PJ_SDP SDP Parsing and Data Structure - * @ingroup PJMEDIA + * @defgroup PJMEDIA_SDP SDP Parsing and Data Structure + * @ingroup PJMEDIA_SESSION * @{ * * The basic SDP session descriptor and elements are described in header diff --git a/pjmedia/include/pjmedia/sdp_neg.h b/pjmedia/include/pjmedia/sdp_neg.h index d2d977e0..f105c42f 100644 --- a/pjmedia/include/pjmedia/sdp_neg.h +++ b/pjmedia/include/pjmedia/sdp_neg.h @@ -25,8 +25,8 @@ * @brief SDP negotiator header file. */ /** - * @defgroup PJ_SDP_NEG SDP Negotiator. - * @ingroup PJMEDIA + * @defgroup PJMEDIA_SDP_NEG SDP Negotiator + * @ingroup PJMEDIA_SESSION * @{ * * The header file <b><pjmedia/sdp_neg.h></b> contains the declaration diff --git a/pjmedia/include/pjmedia/session.h b/pjmedia/include/pjmedia/session.h index 38fe1e2c..ad490669 100644 --- a/pjmedia/include/pjmedia/session.h +++ b/pjmedia/include/pjmedia/session.h @@ -32,8 +32,13 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_SES Media session + * @defgroup PJMEDIA_SESSION Sessions * @ingroup PJMEDIA + */ + +/** + * @defgroup PJMED_SES Media session + * @ingroup PJMEDIA_SESSION * @{ * * A media session represents multimedia communication between two @@ -90,7 +95,6 @@ typedef struct pjmedia_session_info pjmedia_session_info; * @param si Session info structure to be initialized. * @param local Local SDP session descriptor. * @param remote Remote SDP session descriptor. - * @param stream_idx Media stream index in the session descriptor. * * @return PJ_SUCCESS if stream info is successfully initialized. */ @@ -103,7 +107,7 @@ pjmedia_session_info_from_sdp( pj_pool_t *pool, const pjmedia_sdp_session *remote); -/* +/** * This function will initialize the stream info based on information * in both SDP session descriptors for the specified stream index. * The remaining information will be taken from default codec parameters. @@ -263,7 +267,7 @@ PJ_DECL(pj_status_t) pjmedia_session_get_port( pjmedia_session *session, * * @param session The media session. * @param index Stream index. - * @param sta Stream statistic. + * @param stat Stream statistic. * * @return PJ_SUCCESS on success. */ diff --git a/pjmedia/include/pjmedia/silencedet.h b/pjmedia/include/pjmedia/silencedet.h index e6cb55c5..a4958cc5 100644 --- a/pjmedia/include/pjmedia/silencedet.h +++ b/pjmedia/include/pjmedia/silencedet.h @@ -26,6 +26,15 @@ */ #include <pjmedia/types.h> + +/** + * @defgroup PJMEDIA_SILENCEDET Adaptive Silence Detection + * @ingroup PJMEDIA_FRAME_OP + * @brief Adaptive Silence Detector + * @{ + */ + + PJ_BEGIN_DECL @@ -179,5 +188,10 @@ unsigned char linear2ulaw(int pcm_val); PJ_END_DECL +/** + * @} + */ + + #endif /* __PJMEDIA_SILENCE_DET_H__ */ diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h index 6389ecf8..b09d69d3 100644 --- a/pjmedia/include/pjmedia/sound.h +++ b/pjmedia/include/pjmedia/sound.h @@ -30,9 +30,34 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_SND Sound device abstraction. - * @ingroup PJMEDIA + * @defgroup PJMED_SND Sound Hardware Abstraction + * @ingroup PJMED_SND_PORT + * @brief PJMEDIA abstraction for sound device hardware * @{ + * + * This section describes lower level abstraction for sound device + * hardware. Application normally uses the higher layer @ref + * PJMED_SND_PORT abstraction since it works seamlessly with + * @ref PJMEDIA_PORT_CONCEPT. + * + * The sound hardware abstraction basically runs <b>asychronously</b>, + * and application must register callbacks to be called to receive/ + * supply audio frames from/to the sound hardware. + * + * A full duplex sound stream (created with #pjmedia_snd_open()) + * requires application to supply two callbacks: + * - <b><tt>rec_cb</tt></b> callback to be called when it has finished + * capturing one media frame, and + * - <b><tt>play_cb</tt></b> callback to be called when it needs media + * frame to be played to the sound playback hardware. + * + * Half duplex sound stream (created with #pjmedia_snd_open_rec() or + * #pjmedia_snd_open_player()) will only need one of the callback to + * be specified. + * + * After sound stream is created, application need to call + * #pjmedia_snd_stream_start() to start capturing/playing back media + * frames from/to the sound device. */ /** Opaque data type for audio stream. */ @@ -113,7 +138,8 @@ PJ_DECL(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index); /** * Create sound stream for both capturing audio and audio playback, from the * same device. This is the recommended way to create simultaneous recorder - * and player streams, because it should work on backends that does not allow + * and player streams (instead of creating separate capture and playback + * streams), because it works on backends that does not allow * a device to be opened more than once. * * @param rec_id Device index for recorder/capture stream, or diff --git a/pjmedia/include/pjmedia/sound_port.h b/pjmedia/include/pjmedia/sound_port.h index 53fa35a3..15339bcc 100644 --- a/pjmedia/include/pjmedia/sound_port.h +++ b/pjmedia/include/pjmedia/sound_port.h @@ -29,9 +29,36 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_SND_PORT Media Port Connection Abstraction to Sound Device - * @ingroup PJMEDIA - * @{ + * @defgroup PJMED_SND_PORT Sound Device Port + * @ingroup PJMEDIA_PORT_CLOCK + * @brief Media Port Connection Abstraction to the Sound Device + @{ + + As explained in @ref PJMED_SND, the sound hardware abstraction provides + some callbacks for its user: + - it calls <b><tt>rec_cb</tt></b> callback when it has finished capturing + one media frame, and + - it calls <b><tt>play_cb</tt></b> when it needs media frame to be + played to the sound playback hardware. + + The @ref PJMED_SND_PORT (the object being explained here) add a + thin wrapper to the hardware abstraction: + - it will call downstream port's <tt>put_frame()</tt> + when <b><tt>rec_cb()</tt></b> is called (i.e. when the sound hardware + has finished capturing frame), and + - it will call downstream port's <tt>get_frame()</tt> when + <b><tt>play_cb()</tt></b> is called (i.e. every time the + sound hardware needs more frames to be played to the playback hardware). + + This simple abstraction enables media to flow automatically (and + in timely manner) from the downstream media port to the sound device. + In other words, the sound device port supplies media clock to + the ports. The media clock concept is explained in @ref PJMEDIA_PORT_CLOCK + section. + + Application registers downstream port to the sound device port by + calling #pjmedia_snd_port_connect(); + */ /** @@ -168,6 +195,7 @@ PJ_DECL(pjmedia_snd_stream*) pjmedia_snd_port_get_snd_stream( * samples per frame, and bits per sample as the sound device port. * * @param snd_port The sound device port. + * @param port The media port to be connected. * * @return PJ_SUCCESS on success, or the appropriate error * code. diff --git a/pjmedia/include/pjmedia/stream.h b/pjmedia/include/pjmedia/stream.h index e4e6a165..c487d8c2 100644 --- a/pjmedia/include/pjmedia/stream.h +++ b/pjmedia/include/pjmedia/stream.h @@ -30,27 +30,48 @@ #include <pjmedia/endpoint.h> #include <pjmedia/port.h> #include <pjmedia/rtcp.h> +#include <pjmedia/transport.h> #include <pj/sock.h> PJ_BEGIN_DECL /** - * @defgroup PJMED_STRM Media Stream - * @ingroup PJMEDIA + * @defgroup PJMED_STRM Streams + * @ingroup PJMEDIA_PORT + * @brief Media port for communicating with remote peer via the network. * @{ * * A media stream is a bidirectional multimedia communication between two - * endpoints. It corresponds to a media description (m= line) in SDP. + * endpoints. It corresponds to a media description (m= line) in SDP + * session descriptor. * * A media stream consists of two unidirectional channels: * - encoding channel, which transmits unidirectional media to remote, and * - decoding channel, which receives unidirectional media from remote. * - * Application normally does not need to create the stream directly; it - * creates media session instead. The media session will create the media - * streams as necessary, according to the media descriptors that present - * in local and remote SDP. + * A media stream exports media port interface (see @ref PJMEDIA_PORT_CONCEPT) + * and application normally uses this interface to interconnect the stream + * to other PJMEDIA components. + * + * A media stream internally manages the following objects: + * - an instance of media codec (see @ref PJMEDIA_CODEC), + * - an @ref PJMED_JBUF, + * - two instances of RTP sessions (#pjmedia_rtp_session, one for each + * direction), + * - one instance of RTCP session (#pjmedia_rtcp_session), + * - and a reference to media transport to send and receive packets + * to/from the network (see @ref PJMEDIA_TRANSPORT_H). + * + * Streams are created by calling #pjmedia_stream_create(), specifying + * #pjmedia_stream_info structure in the parameter. Application can construct + * the #pjmedia_stream_info structure manually, or use + * #pjmedia_stream_info_from_sdp() or #pjmedia_session_info_from_sdp() + * functions to construct the #pjmedia_stream_info from local and remote + * SDP session descriptors. + * + * Application can also use @ref PJMEDIA_SESSION to indirectly create the + * streams. */ /** @@ -92,89 +113,6 @@ struct pjmedia_stream_info typedef struct pjmedia_stream_info pjmedia_stream_info; -/** - * Opaque declaration for media stream. - */ -typedef struct pjmedia_stream pjmedia_stream; - - -/** - * @see pjmedia_transport_op. - */ -typedef struct pjmedia_transport pjmedia_transport; - - -/** - * This structure describes the operations for the stream transport. - */ -struct pjmedia_transport_op -{ - /** - * This function is called by the stream when the transport is about - * to be used by the stream for the first time, and it tells the transport - * about remote RTP address to send the packet and some callbacks to be - * called for incoming packets. - */ - pj_status_t (*attach)(pjmedia_transport *tp, - pjmedia_stream *strm, - const pj_sockaddr_t *rem_addr, - unsigned addr_len, - void (*rtp_cb)(pjmedia_stream*, - const void*, - pj_ssize_t), - void (*rtcp_cb)(pjmedia_stream*, - const void*, - pj_ssize_t)); - - /** - * This function is called by the stream when the stream is no longer - * need the transport (normally when the stream is about to be closed). - */ - void (*detach)(pjmedia_transport *tp, - pjmedia_stream *strm); - - /** - * This function is called by the stream to send RTP packet using the - * transport. - */ - pj_status_t (*send_rtp)(pjmedia_transport *tp, - const void *pkt, - pj_size_t size); - - /** - * This function is called by the stream to send RTCP packet using the - * transport. - */ - pj_status_t (*send_rtcp)(pjmedia_transport *tp, - const void *pkt, - pj_size_t size); - - /** - * This function can be called to destroy this transport. - */ - pj_status_t (*destroy)(pjmedia_transport *tp); -}; - - -/** - * @see pjmedia_transport_op. - */ -typedef struct pjmedia_transport_op pjmedia_transport_op; - - -/** - * This structure declares stream transport. A stream transport is called - * by the stream to transmit a packet, and will notify stream when - * incoming packet is arrived. - */ -struct pjmedia_transport -{ - char name[PJ_MAX_OBJ_NAME]; - - pjmedia_transport_op *op; -}; - - /** * Create a media stream based on the specified parameter. After the stream diff --git a/pjmedia/include/pjmedia/transport.h b/pjmedia/include/pjmedia/transport.h new file mode 100644 index 00000000..66678d7f --- /dev/null +++ b/pjmedia/include/pjmedia/transport.h @@ -0,0 +1,140 @@ +/* $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_TRANSPORT_H__ +#define __PJMEDIA_TRANSPORT_H__ + + +/** + * @file transport.h Media Transport Interface + * @brief Transport interface. + */ + +#include <pjmedia/types.h> + +/** + * @defgroup PJMEDIA_TRANSPORT Transports + * @ingroup PJMEDIA + * @brief Transports. + * Transport related components. + */ + +/** + * @defgroup PJMEDIA_TRANSPORT_H Network Transport Interface + * @ingroup PJMEDIA_TRANSPORT + * @brief PJMEDIA object for sending/receiving media packets over the network + * @{ + * The media transport (#pjmedia_transport) is the object to send and + * receive media packets over the network. Currently only media @ref PJMED_STRM + * are using the transport. + * + * Although currently only @ref PJMEDIA_TRANSPORT_UDP is implemented, + * media transport interface is intended to support any custom transports. + */ + +PJ_BEGIN_DECL + + +/* + * Forward declaration for media transport. + */ +typedef struct pjmedia_transport pjmedia_transport; + + +/** + * This structure describes the operations for the stream transport. + */ +struct pjmedia_transport_op +{ + /** + * This function is called by the stream when the transport is about + * to be used by the stream for the first time, and it tells the transport + * about remote RTP address to send the packet and some callbacks to be + * called for incoming packets. + */ + pj_status_t (*attach)(pjmedia_transport *tp, + pjmedia_stream *strm, + const pj_sockaddr_t *rem_addr, + unsigned addr_len, + void (*rtp_cb)(pjmedia_stream*, + const void*, + pj_ssize_t), + void (*rtcp_cb)(pjmedia_stream*, + const void*, + pj_ssize_t)); + + /** + * This function is called by the stream when the stream is no longer + * need the transport (normally when the stream is about to be closed). + */ + void (*detach)(pjmedia_transport *tp, + pjmedia_stream *strm); + + /** + * This function is called by the stream to send RTP packet using the + * transport. + */ + pj_status_t (*send_rtp)(pjmedia_transport *tp, + const void *pkt, + pj_size_t size); + + /** + * This function is called by the stream to send RTCP packet using the + * transport. + */ + pj_status_t (*send_rtcp)(pjmedia_transport *tp, + const void *pkt, + pj_size_t size); + + /** + * This function can be called to destroy this transport. + */ + pj_status_t (*destroy)(pjmedia_transport *tp); +}; + + +/** + * @see pjmedia_transport_op. + */ +typedef struct pjmedia_transport_op pjmedia_transport_op; + + +/** + * This structure declares stream transport. A stream transport is called + * by the stream to transmit a packet, and will notify stream when + * incoming packet is arrived. + */ +struct pjmedia_transport +{ + /** Transport name (for logging purpose). */ + char name[PJ_MAX_OBJ_NAME]; + + /** Transport's "virtual" function table. */ + pjmedia_transport_op *op; +}; + + +PJ_END_DECL + +/** + * @} + */ + + +#endif /* __PJMEDIA_TRANSPORT_H__ */ + diff --git a/pjmedia/include/pjmedia/transport_udp.h b/pjmedia/include/pjmedia/transport_udp.h index e0b25ed6..3d7b22ef 100644 --- a/pjmedia/include/pjmedia/transport_udp.h +++ b/pjmedia/include/pjmedia/transport_udp.h @@ -21,7 +21,7 @@ /** - * @file stream_transport_udp.h + * @file transport_udp.h * @brief Stream transport with UDP. */ @@ -29,6 +29,16 @@ /** + * @defgroup PJMEDIA_TRANSPORT_UDP UDP Socket Transport + * @ingroup PJMEDIA_TRANSPORT_H + * @brief Implementation of media transport with UDP sockets. + * @{ + */ + +PJ_BEGIN_DECL + + +/** * Options that can be specified when creating UDP transport. */ enum pjmedia_transport_udp_options @@ -92,6 +102,13 @@ PJ_DECL(pj_status_t) pjmedia_transport_udp_close(pjmedia_transport *tp); +PJ_END_DECL + + +/** + * @} + */ + #endif /* __PJMEDIA_TRANSPORT_UDP_H__ */ diff --git a/pjmedia/include/pjmedia/types.h b/pjmedia/include/pjmedia/types.h index 02edd9ff..d43ef768 100644 --- a/pjmedia/include/pjmedia/types.h +++ b/pjmedia/include/pjmedia/types.h @@ -19,15 +19,37 @@ #ifndef __PJMEDIA_TYPES_H__ #define __PJMEDIA_TYPES_H__ +/** + * @file pjmedia/types.h Basic Types + * @brief Basic PJMEDIA types. + */ + #include <pjmedia/config.h> #include <pj/sock.h> /* pjmedia_sock_info */ #include <pj/string.h> /* pj_memcpy(), pj_memset() */ +/** + * @defgroup PJMEDIA_FRAME_OP Frame Operations + * @ingroup PJMEDIA + */ + +/** + * @defgroup PJMEDIA_MISC Misc + * @ingroup PJMEDIA + */ + +/** + * @defgroup PJMEDIA_TYPES Basic Types + * @ingroup PJMEDIA_BASE + * @brief Basic PJMEDIA types and operations. + * @{ + */ + /** * Top most media type. */ -enum pjmedia_type +typedef enum pjmedia_type { /** No type. */ PJMEDIA_TYPE_NONE = 0, @@ -43,19 +65,14 @@ enum pjmedia_type */ PJMEDIA_TYPE_UNKNOWN = 3, -}; - -/** - * @see pjmedia_type - */ -typedef enum pjmedia_type pjmedia_type; +} pjmedia_type; /** * Media direction. */ -enum pjmedia_dir +typedef enum pjmedia_dir { /** None */ PJMEDIA_DIR_NONE = 0, @@ -69,12 +86,8 @@ enum pjmedia_dir /** Incoming and outgoing stream. */ PJMEDIA_DIR_ENCODING_DECODING = 3, -}; +} pjmedia_dir; -/** - * @see pjmedia_dir - */ -typedef enum pjmedia_dir pjmedia_dir; /* Alternate names for media direction: */ @@ -95,22 +108,50 @@ typedef enum pjmedia_dir pjmedia_dir; #define PJMEDIA_DIR_CAPTURE_PLAYBACK PJMEDIA_DIR_ENCODING_DECODING +/** + * Create 32bit port signature from ASCII characters. + */ +#define PJMEDIA_PORT_SIGNATURE(a,b,c,d) \ + (a<<24 | b<<16 | c<<8 | d) + + /** * Opague declaration of media endpoint. */ typedef struct pjmedia_endpt pjmedia_endpt; +/* + * Forward declaration for stream (needed by transport). + */ +typedef struct pjmedia_stream pjmedia_stream; + + /** - * Media socket info. + * Media socket info is used to describe the underlying sockets + * to be used as media transport. */ typedef struct pjmedia_sock_info { + /** The RTP socket handle */ + pj_sock_t rtp_sock; - pj_sock_t rtp_sock; /**< Socket for RTP. */ - pj_sockaddr_in rtp_addr_name; /**< Local RTP address to be advertised.*/ - pj_sock_t rtcp_sock; /**< Socket for RTCP. */ - pj_sockaddr_in rtcp_addr_name; /**< Local RTCP addr to be advertised. */ + /** Address to be advertised as the local address for the RTP + * socket, which does not need to be equal as the bound + * address (for example, this address can be the address resolved + * with STUN). + */ + pj_sockaddr_in rtp_addr_name; + + /** The RTCP socket handle. */ + pj_sock_t rtcp_sock; + + /** Address to be advertised as the local address for the RTCP + * socket, which does not need to be equal as the bound + * address (for example, this address can be the address resolved + * with STUN). + */ + pj_sockaddr_in rtcp_addr_name; } pjmedia_sock_info; @@ -162,5 +203,10 @@ PJ_INLINE(void) pjmedia_copy_samples(pj_int16_t *dst, const pj_int16_t *src, } +/** + * @} + */ + + #endif /* __PJMEDIA_TYPES_H__ */ diff --git a/pjmedia/include/pjmedia/wav_port.h b/pjmedia/include/pjmedia/wav_port.h index 894db811..6806f33f 100644 --- a/pjmedia/include/pjmedia/wav_port.h +++ b/pjmedia/include/pjmedia/wav_port.h @@ -31,6 +31,26 @@ PJ_BEGIN_DECL /** + * @defgroup PJMEDIA_FILE_PLAY File Player + * @ingroup PJMEDIA_PORT + * @brief WAV File Player + * @{ + */ + +/** + * WAV file player options. + */ +enum pjmedia_file_player_option +{ + /** + * Tell the file player to return NULL frame when the whole + * file has been played. + */ + PJMEDIA_FILE_NO_LOOP = 1, +}; + + +/** * Create a media port to play streams from a WAV file. * * @param pool Pool to create memory buffers for this port. @@ -39,7 +59,7 @@ PJ_BEGIN_DECL * from this port. If the value is zero, the default * duration (20ms) will be used. * @param flags Port creation flags. - * @param buf_size Buffer size to be allocated. If the value is zero or + * @param buff_size Buffer size to be allocated. If the value is zero or * negative, the port will use default buffer size (which * is about 4KB). * @param user_data User data to be associated with the file player port. @@ -69,18 +89,32 @@ PJ_DECL(pj_status_t) pjmedia_wav_player_port_set_pos( pjmedia_port *port, /** + * @} + */ + + +/** + * @defgroup PJMEDIA_FILE_REC File Writer (Recorder) + * @ingroup PJMEDIA_PORT + * @brief WAV File Writer (Recorder) + * @{ + */ + + + +/** * Create a media port to record streams to a WAV file. Note that the port * must be closed properly (with #pjmedia_port_destroy()) so that the WAV * header can be filled with correct values (such as the file length). * - * @param pool Pool to create memory buffers for this port. - * @param filename File name. - * @param clock_rate The sampling rate. - * @param channel_count Number of channels. + * @param pool Pool to create memory buffers for this port. + * @param filename File name. + * @param clock_rate The sampling rate. + * @param channel_count Number of channels. * @param samples_per_frame Number of samples per frame. - * @param bits_per_sampe Number of bits per sample (eg 16). - * @param flags Port creation flags (must be 0 at present). - * @param buf_size Buffer size to be allocated. If the value is zero or + * @param bits_per_sample Number of bits per sample (eg 16). + * @param flags Port creation flags (must be 0 at present). + * @param buff_size Buffer size to be allocated. If the value is zero or * negative, the port will use default buffer size (which * is about 4KB). * @param user_data User data to be associated with the file writer port. @@ -101,6 +135,10 @@ PJ_DECL(pj_status_t) pjmedia_wav_writer_port_create(pj_pool_t *pool, +/** + * @} + */ + PJ_END_DECL diff --git a/pjmedia/include/pjmedia/wave.h b/pjmedia/include/pjmedia/wave.h index 201f9760..9727a9bd 100644 --- a/pjmedia/include/pjmedia/wave.h +++ b/pjmedia/include/pjmedia/wave.h @@ -27,11 +27,35 @@ #include <pjmedia/types.h> +/** + * @defgroup PJMEDIA_WAVE WAVE Header + * @ingroup PJMEDIA_MISC + * @{ + * + * Supports for simple/canonical Microsoft RIFF WAVE format. + */ + + PJ_BEGIN_DECL +/** + * Standard RIFF tag to identify RIFF file format in the WAVE header. + */ #define PJMEDIA_RIFF_TAG ('F'<<24|'F'<<16|'I'<<8|'R') + +/** + * Standard WAVE tag to identify WAVE header. + */ #define PJMEDIA_WAVE_TAG ('E'<<24|'V'<<16|'A'<<8|'W') + +/** + * Standard FMT tag to identify format chunks. + */ #define PJMEDIA_FMT_TAG (' '<<24|'t'<<16|'m'<<8|'f') + +/** + * Standard DATA tag to identify data chunks. + */ #define PJMEDIA_DATA_TAG ('a'<<24|'t'<<16|'a'<<8|'d') @@ -41,26 +65,29 @@ PJ_BEGIN_DECL */ struct pjmedia_wave_hdr { + /** This structure describes RIFF WAVE file header */ struct { - pj_uint32_t riff; - pj_uint32_t file_len; - pj_uint32_t wave; + pj_uint32_t riff; /**< "RIFF" ASCII tag. */ + pj_uint32_t file_len; /**< File length minus 8 bytes */ + pj_uint32_t wave; /**< "WAVE" ASCII tag. */ } riff_hdr; + /** This structure describes format chunks/header */ struct { - pj_uint32_t fmt; - pj_uint32_t len; - pj_uint16_t fmt_tag; - pj_uint16_t nchan; - pj_uint32_t sample_rate; - pj_uint32_t bytes_per_sec; - pj_uint16_t block_align; - pj_uint16_t bits_per_sample; + pj_uint32_t fmt; /**< "fmt " ASCII tag. */ + pj_uint32_t len; /**< 16 for PCM. */ + pj_uint16_t fmt_tag; /**< 1 for PCM */ + pj_uint16_t nchan; /**< Number of channels. */ + pj_uint32_t sample_rate; /**< Sampling rate. */ + pj_uint32_t bytes_per_sec; /**< Average bytes per second. */ + pj_uint16_t block_align; /**< nchannels * bits / 8 */ + pj_uint16_t bits_per_sample; /**< Bits per sample. */ } fmt_hdr; + /** The data header preceeds the actual data in the file. */ struct { - pj_uint32_t data; - pj_uint32_t len; + pj_uint32_t data; /**< "data" ASCII tag. */ + pj_uint32_t len; /**< Data length. */ } data_hdr; }; @@ -98,5 +125,10 @@ PJ_DECL(void) pjmedia_wave_hdr_host_to_file( pjmedia_wave_hdr *hdr ); PJ_END_DECL +/** + * @} + */ + + #endif /* __PJMEDIA_WAVE_H__ */ diff --git a/pjmedia/src/pjmedia/port.c b/pjmedia/src/pjmedia/port.c index 50a008e9..96c07c08 100644 --- a/pjmedia/src/pjmedia/port.c +++ b/pjmedia/src/pjmedia/port.c @@ -25,84 +25,6 @@ /** - * Connect two ports. - */ -PJ_DEF(pj_status_t) pjmedia_port_connect( pj_pool_t *pool, - pjmedia_port *upstream_port, - pjmedia_port *downstream_port) -{ - pj_status_t status; - - PJ_ASSERT_RETURN(pool && upstream_port && downstream_port, PJ_EINVAL); - -#if 0 - /* They both MUST have the same media type. */ - PJ_ASSERT_RETURN(upstream_port->info.type == - downstream_port->info.type, PJMEDIA_ENCTYPE); - - /* They both MUST have the same clock rate. */ - PJ_ASSERT_RETURN(upstream_port->info.sample_rate == - downstream_port->info.sample_rate, PJMEDIA_ENCCLOCKRATE); - - /* They both MUST have the same samples per frame */ - PJ_ASSERT_RETURN(upstream_port->info.samples_per_frame == - downstream_port->info.samples_per_frame, - PJMEDIA_ENCSAMPLESPFRAME); - - /* They both MUST have the same bits per sample */ - PJ_ASSERT_RETURN(upstream_port->info.bits_per_sample == - downstream_port->info.bits_per_sample, - PJMEDIA_ENCBITS); - - /* They both MUST have the same bytes per frame */ - PJ_ASSERT_RETURN(upstream_port->info.bytes_per_frame == - downstream_port->info.bytes_per_frame, - PJMEDIA_ENCBYTES); -#endif - - /* Create mutual attachment. */ - if (upstream_port->on_downstream_connect) { - status = upstream_port->on_downstream_connect( pool, upstream_port, - downstream_port ); - if (status != PJ_SUCCESS) - return status; - } - - if (downstream_port->on_upstream_connect) { - status = downstream_port->on_upstream_connect( pool, downstream_port, - upstream_port ); - if (status != PJ_SUCCESS) - return status; - } - - /* Save the attachment. */ - upstream_port->downstream_port = downstream_port; - downstream_port->upstream_port = upstream_port; - - /* Done. */ - return PJ_SUCCESS; -} - - -/** - * Disconnect ports. - */ -PJ_DEF(pj_status_t) pjmedia_port_disconnect( pjmedia_port *upstream_port, - pjmedia_port *downstream_port) -{ - PJ_ASSERT_RETURN(upstream_port && downstream_port, PJ_EINVAL); - - if (upstream_port->downstream_port == downstream_port) - upstream_port->downstream_port = NULL; - - if (downstream_port->upstream_port == upstream_port) - downstream_port->upstream_port = NULL; - - return PJ_SUCCESS; -} - - -/** * Get a frame from the port (and subsequent downstream ports). */ PJ_DEF(pj_status_t) pjmedia_port_get_frame( pjmedia_port *port, @@ -115,7 +37,6 @@ PJ_DEF(pj_status_t) pjmedia_port_get_frame( pjmedia_port *port, } - /** * Put a frame to the port (and subsequent downstream ports). */ @@ -139,16 +60,6 @@ PJ_DEF(pj_status_t) pjmedia_port_destroy( pjmedia_port *port ) PJ_ASSERT_RETURN(port, PJ_EINVAL); - /* Recursively call this function again to destroy downstream - * port first. - */ - if (port->downstream_port) { - status = pjmedia_port_destroy(port->downstream_port); - if (status != PJ_SUCCESS) - return status; - pjmedia_port_disconnect(port, port->downstream_port); - } - if (port->on_destroy) status = port->on_destroy(port); else @@ -159,4 +70,3 @@ PJ_DEF(pj_status_t) pjmedia_port_destroy( pjmedia_port *port ) - diff --git a/pjmedia/src/pjmedia/resample_port.c b/pjmedia/src/pjmedia/resample_port.c index 8dad6430..ca128515 100644 --- a/pjmedia/src/pjmedia/resample_port.c +++ b/pjmedia/src/pjmedia/resample_port.c @@ -28,12 +28,12 @@ struct resample_port { pjmedia_port base; + pjmedia_port *dn_port; + unsigned options; pjmedia_resample *resample_get; pjmedia_resample *resample_put; pj_int16_t *get_buf; pj_int16_t *put_buf; - unsigned downstream_frame_size; - unsigned upstream_frame_size; }; @@ -42,74 +42,86 @@ static pj_status_t resample_put_frame(pjmedia_port *this_port, const pjmedia_frame *frame); static pj_status_t resample_get_frame(pjmedia_port *this_port, pjmedia_frame *frame); +static pj_status_t resample_destroy(pjmedia_port *this_port); PJ_DEF(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool, - pj_bool_t high_quality, - pj_bool_t large_filter, - unsigned downstream_rate, - unsigned upstream_rate, - unsigned channel_count, - unsigned samples_per_frame, - pjmedia_port **p_port ) + pjmedia_port *dn_port, + unsigned clock_rate, + unsigned opt, + pjmedia_port **p_port ) { struct resample_port *rport; - unsigned upstream_samples_per_frame; + unsigned ptime; pj_status_t status; - PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); + /* Validate arguments. */ + PJ_ASSERT_RETURN(pool && dn_port && clock_rate && p_port, PJ_EINVAL); - upstream_samples_per_frame = (unsigned)(samples_per_frame * 1.0 * - upstream_rate / downstream_rate); + /* Only supports 16bit samples per frame */ + PJ_ASSERT_RETURN(dn_port->info.bits_per_sample == 16, PJMEDIA_ENCBITS); + ptime = dn_port->info.samples_per_frame * 1000 / + dn_port->info.clock_rate; + /* Create and initialize port. */ rport = pj_pool_zalloc(pool, sizeof(struct resample_port)); PJ_ASSERT_RETURN(rport != NULL, PJ_ENOMEM); - rport->base.info.bits_per_sample = 16; - rport->base.info.bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; - rport->base.info.channel_count = channel_count; + rport->base.info.clock_rate = clock_rate; + rport->base.info.samples_per_frame = clock_rate * ptime / 1000; + rport->base.info.bytes_per_frame = rport->base.info.samples_per_frame * + BYTES_PER_SAMPLE; + rport->base.info.bits_per_sample = BYTES_PER_SAMPLE * 8; + rport->base.info.channel_count = dn_port->info.channel_count; rport->base.info.encoding_name = pj_str("pcm"); rport->base.info.has_info = 1; rport->base.info.name = pj_str("resample"); rport->base.info.need_info = 0; rport->base.info.pt = 0xFF; - rport->base.info.clock_rate = upstream_rate; - rport->base.info.samples_per_frame = upstream_samples_per_frame; - rport->base.info.signature = 0; + rport->base.info.signature = PJMEDIA_PORT_SIGNATURE('R','S','M','P'); rport->base.info.type = PJMEDIA_TYPE_AUDIO; - rport->downstream_frame_size = samples_per_frame; - rport->upstream_frame_size = upstream_samples_per_frame; + rport->dn_port = dn_port; + rport->options = opt; + /* Create buffers. * We need separate buffer for get_frame() and put_frame() since * both functions may run simultaneously. */ - rport->get_buf = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE); - PJ_ASSERT_RETURN(rport->get_buf, PJ_ENOMEM); + rport->get_buf = pj_pool_alloc(pool, rport->base.info.bytes_per_frame); + PJ_ASSERT_RETURN(rport->get_buf != NULL, PJ_ENOMEM); - rport->put_buf = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE); - PJ_ASSERT_RETURN(rport->put_buf, PJ_ENOMEM); + rport->put_buf = pj_pool_alloc(pool, rport->base.info.bytes_per_frame); + PJ_ASSERT_RETURN(rport->put_buf != NULL, PJ_ENOMEM); /* Create "get_frame" resample */ - status = pjmedia_resample_create( pool, high_quality, large_filter, - downstream_rate, upstream_rate, - samples_per_frame, &rport->resample_get); + status = pjmedia_resample_create(pool, + (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, + (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0, + dn_port->info.clock_rate, + rport->base.info.clock_rate, + dn_port->info.samples_per_frame, + &rport->resample_get); if (status != PJ_SUCCESS) return status; /* Create "put_frame" resample */ - status = pjmedia_resample_create( pool, high_quality, large_filter, - upstream_rate, downstream_rate, - upstream_samples_per_frame, - &rport->resample_put); - - /* Set get_frame and put_frame interface */ + status = pjmedia_resample_create(pool, + (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, + (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0, + rport->base.info.clock_rate, + dn_port->info.clock_rate, + rport->base.info.samples_per_frame, + &rport->resample_put); + + /* Media port interface */ rport->base.get_frame = &resample_get_frame; rport->base.put_frame = &resample_put_frame; + rport->base.on_destroy = &resample_destroy; /* Done */ @@ -127,16 +139,16 @@ static pj_status_t resample_put_frame(pjmedia_port *this_port, pjmedia_frame downstream_frame; /* Return if we don't have downstream port. */ - if (this_port->downstream_port == NULL) { + if (rport->dn_port == NULL) { return PJ_SUCCESS; } if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO) { - pjmedia_resample_run( rport->resample_put, frame->buf, rport->put_buf); + pjmedia_resample_run( rport->resample_put, frame->buf, + rport->put_buf); downstream_frame.buf = rport->put_buf; - downstream_frame.size = rport->downstream_frame_size * - BYTES_PER_SAMPLE; + downstream_frame.size = rport->dn_port->info.bytes_per_frame; } else { downstream_frame.buf = frame->buf; downstream_frame.size = frame->size; @@ -145,8 +157,7 @@ static pj_status_t resample_put_frame(pjmedia_port *this_port, downstream_frame.type = frame->type; downstream_frame.timestamp.u64 = frame->timestamp.u64; - return pjmedia_port_put_frame( this_port->downstream_port, - &downstream_frame ); + return pjmedia_port_put_frame( rport->dn_port, &downstream_frame ); } @@ -155,31 +166,53 @@ static pj_status_t resample_get_frame(pjmedia_port *this_port, pjmedia_frame *frame) { struct resample_port *rport = (struct resample_port*) this_port; - pjmedia_frame downstream_frame; + pjmedia_frame tmp_frame; pj_status_t status; /* Return silence if we don't have downstream port */ - if (this_port->downstream_port == NULL) { + if (rport->dn_port == NULL) { pj_memset(frame->buf, frame->size, 0); return PJ_SUCCESS; } - downstream_frame.buf = rport->get_buf; - downstream_frame.size = rport->downstream_frame_size * BYTES_PER_SAMPLE; - downstream_frame.timestamp.u64 = frame->timestamp.u64; - downstream_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; + tmp_frame.buf = rport->get_buf; + tmp_frame.size = rport->dn_port->info.bytes_per_frame; + tmp_frame.timestamp.u64 = frame->timestamp.u64; + tmp_frame.type = PJMEDIA_FRAME_TYPE_AUDIO; - status = pjmedia_port_get_frame( this_port->downstream_port, - &downstream_frame); + status = pjmedia_port_get_frame( rport->dn_port, &tmp_frame); if (status != PJ_SUCCESS) return status; - pjmedia_resample_run( rport->resample_get, rport->get_buf, frame->buf); + if (tmp_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) { + frame->type = tmp_frame.type; + frame->timestamp = tmp_frame.timestamp; + frame->size = tmp_frame.size; + if (tmp_frame.size) + pj_memcpy(frame->buf, tmp_frame.buf, tmp_frame.size); + return PJ_SUCCESS; + } - frame->size = rport->upstream_frame_size * BYTES_PER_SAMPLE; + pjmedia_resample_run( rport->resample_get, tmp_frame.buf, frame->buf); + + frame->size = rport->base.info.bytes_per_frame; frame->type = PJMEDIA_FRAME_TYPE_AUDIO; return PJ_SUCCESS; } +static pj_status_t resample_destroy(pjmedia_port *this_port) +{ + struct resample_port *rport = (struct resample_port*) this_port; + + if ((rport->options & PJMEDIA_RESAMPLE_DONT_DESTROY_DN)==0) { + pjmedia_port_destroy(rport->dn_port); + rport->dn_port = NULL; + } + + /* Nothing else to do */ + + return PJ_SUCCESS; +} + diff --git a/pjmedia/src/pjmedia/wav_player.c b/pjmedia/src/pjmedia/wav_player.c index 060055d2..e7c3df40 100644 --- a/pjmedia/src/pjmedia/wav_player.c +++ b/pjmedia/src/pjmedia/wav_player.c @@ -55,6 +55,8 @@ struct file_port { pjmedia_port base; + unsigned options; + pj_bool_t eof; pj_size_t bufsize; char *buf; char *readpos; @@ -114,6 +116,10 @@ static pj_status_t fill_buffer(struct file_port *fport) pj_ssize_t size; pj_status_t status; + if (fport->eof) { + return PJ_EEOF; + } + while (size_left > 0) { /* Calculate how many bytes to read in this run. */ @@ -135,11 +141,19 @@ static pj_status_t fill_buffer(struct file_port *fport) * encountered EOF. Rewind the file. */ if (size < (pj_ssize_t)size_to_read) { - PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..", - (int)fport->base.info.name.slen, - fport->base.info.name.ptr)); - fport->fpos = sizeof(struct pjmedia_wave_hdr); - pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET); + if (fport->options & PJMEDIA_FILE_NO_LOOP) { + PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, stopping..", + (int)fport->base.info.name.slen, + fport->base.info.name.ptr)); + fport->eof = PJ_TRUE; + return PJ_EEOF; + } else { + PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..", + (int)fport->base.info.name.slen, + fport->base.info.name.ptr)); + fport->fpos = sizeof(struct pjmedia_wave_hdr); + pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET); + } } } @@ -156,7 +170,7 @@ static pj_status_t fill_buffer(struct file_port *fport) PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool, const char *filename, unsigned ptime, - unsigned flags, + unsigned options, pj_ssize_t buff_size, void *user_data, pjmedia_port **p_port ) @@ -167,8 +181,6 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool, pj_status_t status; - PJ_UNUSED_ARG(flags); - /* Check arguments. */ PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL); @@ -260,6 +272,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool, /* Initialize */ fport->base.user_data = user_data; + fport->options = options; /* Update port info. */ fport->base.info.channel_count = wave_hdr.fmt_hdr.nchan; @@ -337,6 +350,7 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_set_pos(pjmedia_port *port, samples * BYTES_PER_SAMPLE; pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET); + fport->eof = PJ_FALSE; return fill_buffer(fport); } @@ -384,8 +398,11 @@ static pj_status_t file_get_frame(pjmedia_port *this_port, fport->readpos = fport->buf; status = fill_buffer(fport); - if (status != PJ_SUCCESS) + if (status != PJ_SUCCESS) { + frame->type = PJMEDIA_FRAME_TYPE_NONE; + frame->size = 0; return status; + } } } else { unsigned endread; diff --git a/pjsip-apps/src/samples/resampleplay.c b/pjsip-apps/src/samples/resampleplay.c index e4440e15..f8768591 100644 --- a/pjsip-apps/src/samples/resampleplay.c +++ b/pjsip-apps/src/samples/resampleplay.c @@ -127,27 +127,14 @@ int main(int argc, char *argv[]) //ptime = samples_per_frame * 1000 / sampling_rate; /* Create the resample port. */ - status = pjmedia_resample_port_create( pool, 1, 1, - file_port->info.clock_rate, - sampling_rate, - channel_count, - (unsigned)( - samples_per_frame * 1.0 * - file_port->info.clock_rate / - sampling_rate), + status = pjmedia_resample_port_create( pool, file_port, + sampling_rate, 0, &resample_port); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create resample port", status); return 1; } - /* Connect resample port to file port */ - status = pjmedia_port_connect( pool, resample_port, file_port); - if (status != PJ_SUCCESS) { - app_perror(THIS_FILE, "Error connecting ports", status); - return 1; - } - /* Create sound player port. */ status = pjmedia_snd_port_create( pool, /* pool */ |