diff options
31 files changed, 693 insertions, 47 deletions
diff --git a/pjmedia/docs/doxygen.cfg b/pjmedia/docs/doxygen.cfg index 1a466a43..5397ade6 100644 --- a/pjmedia/docs/doxygen.cfg +++ b/pjmedia/docs/doxygen.cfg @@ -345,7 +345,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = include
+INPUT = include ../pjsip-apps/src/samples
# 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
@@ -354,7 +354,7 @@ INPUT = include # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
# *.h++ *.idl *.odl
-FILE_PATTERNS = *.h
+FILE_PATTERNS = *.h *.c
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@@ -383,7 +383,7 @@ EXCLUDE_PATTERNS = # directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH =
+EXAMPLE_PATH = ../pjsip-apps/src/samples
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
diff --git a/pjmedia/docs/siprtp.jpg b/pjmedia/docs/siprtp.jpg Binary files differnew file mode 100644 index 00000000..975f1fad --- /dev/null +++ b/pjmedia/docs/siprtp.jpg diff --git a/pjmedia/docs/sndtest.jpg b/pjmedia/docs/sndtest.jpg Binary files differnew file mode 100644 index 00000000..ba1ab980 --- /dev/null +++ b/pjmedia/docs/sndtest.jpg diff --git a/pjmedia/include/pjmedia-codec.h b/pjmedia/include/pjmedia-codec.h index f160edef..3658cb10 100644 --- a/pjmedia/include/pjmedia-codec.h +++ b/pjmedia/include/pjmedia-codec.h @@ -19,6 +19,11 @@ #ifndef __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ #define __PJMEDIA_CODEC_PJMEDIA_CODEC_H__ +/** + * @file pjmedia-codec.h + * @brief Include all codecs API in PJMEDIA-CODEC + */ + #include <pjmedia-codec/l16.h> #include <pjmedia-codec/gsm.h> #include <pjmedia-codec/speex.h> diff --git a/pjmedia/include/pjmedia-codec/gsm.h b/pjmedia/include/pjmedia-codec/gsm.h index 04f526ad..f6d0e99f 100644 --- a/pjmedia/include/pjmedia-codec/gsm.h +++ b/pjmedia/include/pjmedia-codec/gsm.h @@ -27,7 +27,7 @@ #include <pjmedia-codec/types.h> /** - * @defgroup PJMED_GSM GSM 06.10 + * @defgroup PJMED_GSM GSM 06.10 Codec * @ingroup PJMEDIA_CODEC * @brief Implementation of GSM FR based on GSM 06.10 library * @{ diff --git a/pjmedia/include/pjmedia-codec/l16.h b/pjmedia/include/pjmedia-codec/l16.h index 225c0929..59e222e1 100644 --- a/pjmedia/include/pjmedia-codec/l16.h +++ b/pjmedia/include/pjmedia-codec/l16.h @@ -23,7 +23,7 @@ /** - * @defgroup PJMED_L16 L16 Family + * @defgroup PJMED_L16 L16 Codec Family * @ingroup PJMEDIA_CODEC * @brief 16bit linear codecs (useful for debugging) * @{ diff --git a/pjmedia/include/pjmedia-codec/speex.h b/pjmedia/include/pjmedia-codec/speex.h index a773b39e..51b6931c 100644 --- a/pjmedia/include/pjmedia-codec/speex.h +++ b/pjmedia/include/pjmedia-codec/speex.h @@ -27,7 +27,7 @@ #include <pjmedia-codec/types.h> /** - * @defgroup PJMED_SPEEX Speex + * @defgroup PJMED_SPEEX Speex Codec Family * @ingroup PJMEDIA_CODEC * @brief Implementation of Speex codecs (narrow/wide/ultrawide-band). * @{ diff --git a/pjmedia/include/pjmedia/doxygen.h b/pjmedia/include/pjmedia/doxygen.h index 9ebd27e6..c9bef719 100644 --- a/pjmedia/include/pjmedia/doxygen.h +++ b/pjmedia/include/pjmedia/doxygen.h @@ -61,9 +61,63 @@ * PJMEDIA-CODEC. * * \n + * @section main_page_get_start_sec Getting Started + * + * For those who likes to just get start coding, the @ref getting_started_pjmedia + * may be a good place to start. + * + * The @ref page_pjmedia_samples page describes some examples that are available + * in the source tree. + * + * + * \n * @section pjmedia_lic Copying and Acknowledgements * - * Please see @ref lic_stuffs page for the details. + * PJMEDIA and PJMEDIA-CODEC contains various parts obtained from other + * places, and each of these would have their own licensing terms. + * Please see @ref lic_stuffs page for details. + * + */ + +/** + * @page pjmed_keywords_page Features Index + * @section pjmed_keywords Features Index + * + * <b>PJMEDIA features</b>, in no particular order (click to go to the relevant + * documentation): + * @ref lic_stuffs "Open Source media stack", + * @ref PJMEDIA_CLOCK, + * @ref PJMEDIA_CODEC, + * @ref enc_dec_codec, + * @ref plc_codec, + * @ref PJMEDIA_CONF, + * @ref PJMED_G711 "G711/G.711 (PCMA/PCMU) codec with PLC", + * @ref PJMED_GSM "GSM codec with PLC", + * @ref PJMED_L16 "linear codecs (multiple clockrate, stereo support, etc)", + * @ref PJMED_SPEEX "Speex codec (narrowband, wideband, ultra-wideband)", + * @ref PJMED_JBUF "portable, adaptive jitter buffer with PLC support", + * @ref PJMEDIA_MASTER_PORT, + * @ref PJMEDIA_NULL_PORT, + * @ref PJMED_PLC, + * @ref PJMEDIA_PORT_CONCEPT, + * @ref PJMEDIA_PORT_CLOCK, + * @ref PJMEDIA_RESAMPLE "high quality resampling/sampling rate conversion", + * @ref PJMEDIA_RESAMPLE_PORT, + * @ref PJMED_RTCP "small footprint, portable RTCP with media quality statistics", + * @ref PJMED_RTP "very small footprint, modular, DSP ready RTP implementation", + * @ref PJMEDIA_SDP "modular, small footprint, open source SDP implementation", + * @ref PJMEDIA_SDP_NEG "modular SDP negotiation/negotiator abstraction", + * @ref PJMED_SES "media session abstraction", + * @ref PJMEDIA_SILENCEDET, + * @ref PJMED_SND "portable audio/sound hardware/device abstraction for Linux, Unix, Windows, DirectSound, WinCE, Windows Mobile, MacOS X, etc.", + * @ref PJMED_SND_PORT, + * @ref PJMEDIA_SPLITCOMB, + * @ref PJMED_STRM "remote stream", + * @ref PJMEDIA_TRANSPORT_H "custom media transport abstraction", + * @ref PJMEDIA_TRANSPORT_UDP, + * @ref PJMEDIA_FILE_PLAY "WAV/WAVE file playback", + * @ref PJMEDIA_FILE_REC "WAV/WAVE file recording/capture", + * @ref PJMEDIA_WAVE "portable WAV/WAVE header manipulation" */ @@ -325,4 +379,141 @@ * */ + +/** + @page getting_started_pjmedia Getting Started with PJMEDIA + + @section getstart_init_setup_build Setting-up the Build System + + @subsection subsec_build_pjmedia Building PJMEDIA and PJMEDIA-CODEC + + The PJMEDIA and PJMEDIA-CODEC libraries are normally bundled in PJPROJECT + source tarball, and they are located in <tt><b>pjmedia</b></tt> sub-directory + tree. + + Please follow the instructions in <tt><b>INSTALL.txt</b></tt> in the root + PJPROJECT directory to build all projects, including PJMEDIA and PJMEDIA-CODEC. + + @subsection subsec_config_build Setting Up the Build Environment + + In your project, you will need to configure the following. + - Add <tt><b>$pjproject/pjmedia/include</b></tt> in the search path for + include files. + - Add <tt><b>$pjproject/pjmedia/lib</b></tt> in the search path for + library files. + - Add PJMEDIA and PJMEDIA static libraries in the link command. + + @subsection subsec_inc_pjmedia Include PJMEDIA and PJMEDIA-CODEC in Source Files + + To include all features from PJMEDIA and PJMEDIA-CODEC, use the following: + + \code + #include <pjlib.h> + #include <pjmedia.h> + #include <pjmedia-codec.h> + \endcode + + Alternatively, you may include only specific parts of the library (for example + to speed up compilation by just a fraction), for example: + + \code + #include <pjmedia/conference.h> + #include <pjmedia/jbuf.h> + #include <pjmedia-codec/speex.h> + \endcode + + Note that you need to give <b>"pjmedia/"</b> and <b>"pjmedia-codec/"</b> + prefix to include specific files. + + + @section getstart_using Using PJMEDIA + + I wish I could explain more, but for now, please have a look at the + @ref page_pjmedia_samples page on some examples. + */ + +/** + @page page_pjmedia_samples PJMEDIA and PJMEDIA-CODEC Examples + + @section pjmedia_samples_sec PJMEDIA and PJMEDIA-CODEC Examples + + Please find below some PJMEDIA related examples that may help in giving + some more info: + + - @ref page_pjmedia_samples_level_c\n + This is a good place to start learning about @ref PJMEDIA_PORT_CONCEPT, + as it shows that @ref PJMEDIA_PORT_CONCEPT are only "passive" objects + with <tt>get_frame()</tt> and <tt>put_frame()</tt> interface, and + someone has to call these to retrieve/store media frames. + + - @ref page_pjmedia_samples_playfile_c\n + This example shows that when application connects a media port (in this + case a @ref PJMEDIA_FILE_PLAY) to @ref PJMED_SND_PORT, media will flow + automatically since the @ref PJMED_SND_PORT provides @ref PJMEDIA_PORT_CLOCK. + + - @ref page_pjmedia_samples_recfile_c\n + Demonstrates how to capture audio from microphone to WAV file. + + - @ref page_pjmedia_samples_playsine_c\n + Demonstrates how to create a custom @ref PJMEDIA_PORT_CONCEPT (in this + case a sine wave generator) and integrate it to PJMEDIA. + + - @ref page_pjmedia_samples_confsample_c\n + This demonstrates how to use the @ref PJMEDIA_CONF. The sample program can + open multiple WAV files, and instruct the conference bridge to mix the + signal before playing it to the sound device. + + - @ref page_pjmedia_samples_confbench_c\n + I use this to benchmark/optimize the conference bridge algorithm, but + readers may find the source useful. + + - @ref page_pjmedia_samples_resampleplay_c\n + Demonstrates how to use @ref PJMEDIA_RESAMPLE_PORT to change the + sampling rate of a media port (in this case, a @ref PJMEDIA_FILE_PLAY). + + - @ref page_pjmedia_samples_sndtest_c\n + This program performs some tests to the sound device to get some + quality parameters (such as sound jitter and clock drifts).\n + Screenshots on WinXP: \image html sndtest.jpg "sndtest screenshot on WinXP" + + - @ref page_pjmedia_samples_streamutil_c\n + This example mainly demonstrates how to stream media (in this case a + @ref PJMEDIA_FILE_PLAY) to remote peer using RTP. + + - @ref page_pjmedia_samples_siprtp_c\n + This is a useful program (integrated with PJSIP) to actively measure + the network quality/impairment parameters by making one or more SIP + calls (or receiving one or more SIP calls) and display the network + impairment of each stream direction at the end of the call. + The program is able to measure network quality parameters such as + jitter, packet lost/reorder/duplicate, round trip time, etc.\n + Note that the remote peer MUST support RTCP so that network quality + of each direction can be calculated. Using siprtp for both endpoints + is recommended.\n + Screenshots on WinXP: \image html siprtp.jpg "siprtp screenshot on WinXP" + + */ + +/** + * \page page_pjmedia_samples_siprtp_c Samples: Using SIP and Custom RTP/RTCP to Monitor Quality + * + * This source is an example to demonstrate using SIP and RTP/RTCP framework + * to measure the network quality/impairment from the SIP call. This + * program can be used to make calls or to receive calls from other + * SIP endpoint (or other siprtp program), and to display the media + * quality statistics at the end of the call. + * + * Note that the remote peer must support RTCP. + * + * The layout of the program has been designed so that custom reporting + * can be generated instead of plain human readable text. + * + * The source code of the file is pjsip-apps/src/samples/siprtp.c + * + * Screenshots on WinXP: \image html siprtp.jpg + * + * \includelineno siprtp.c + */ + #endif /* __PJMEDIA_DOXYGEN_H__ */ + diff --git a/pjmedia/include/pjmedia/plc.h b/pjmedia/include/pjmedia/plc.h index 6b80d18a..6a4be4d2 100644 --- a/pjmedia/include/pjmedia/plc.h +++ b/pjmedia/include/pjmedia/plc.h @@ -27,7 +27,7 @@ #include <pjmedia/types.h> /** - * @defgroup PJMED_PLC Packet Lost Concealment + * @defgroup PJMED_PLC Packet Lost Concealment (PLC) * @ingroup PJMEDIA_FRAME_OP * @{ * This section describes PJMEDIA's implementation of Packet Lost diff --git a/pjmedia/include/pjmedia/rtp.h b/pjmedia/include/pjmedia/rtp.h index edad178a..220a8634 100644 --- a/pjmedia/include/pjmedia/rtp.h +++ b/pjmedia/include/pjmedia/rtp.h @@ -37,7 +37,8 @@ PJ_BEGIN_DECL * * 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. + * on any transports (sockets), to promote even more use, such as in DSP + * development (where transport may be handled by different processor). * * An RTCP implementation is available, in separate module. Please see * @ref PJMED_RTCP. diff --git a/pjmedia/include/pjmedia/sdp_neg.h b/pjmedia/include/pjmedia/sdp_neg.h index f105c42f..4a07cfe6 100644 --- a/pjmedia/include/pjmedia/sdp_neg.h +++ b/pjmedia/include/pjmedia/sdp_neg.h @@ -25,8 +25,9 @@ * @brief SDP negotiator header file. */ /** - * @defgroup PJMEDIA_SDP_NEG SDP Negotiator + * @defgroup PJMEDIA_SDP_NEG SDP Negotiation * @ingroup PJMEDIA_SESSION + * @brief Abstraction to perform SDP negotiation * @{ * * The header file <b><pjmedia/sdp_neg.h></b> contains the declaration diff --git a/pjmedia/include/pjmedia/sound.h b/pjmedia/include/pjmedia/sound.h index b09d69d3..9cd2bbca 100644 --- a/pjmedia/include/pjmedia/sound.h +++ b/pjmedia/include/pjmedia/sound.h @@ -30,7 +30,7 @@ PJ_BEGIN_DECL /** - * @defgroup PJMED_SND Sound Hardware Abstraction + * @defgroup PJMED_SND Portable Sound Hardware Abstraction * @ingroup PJMED_SND_PORT * @brief PJMEDIA abstraction for sound device hardware * @{ diff --git a/pjmedia/include/pjmedia/splitcomb.h b/pjmedia/include/pjmedia/splitcomb.h index 1bd1bd23..d1104488 100644 --- a/pjmedia/include/pjmedia/splitcomb.h +++ b/pjmedia/include/pjmedia/splitcomb.h @@ -21,6 +21,25 @@ /** + * @file splitcomb.h + * @brief Media channel splitter/combiner port. + */ +#include <pjmedia/types.h> + + +/** + * @addtogroup PJMEDIA_SPLITCOMB Media channel splitter/combiner + * @ingroup PJMEDIA_PORT + * @brief Split and combine media channels in media streams + * @{ + * This section describes media port to split and combine media + * channels in the stream. + */ + +PJ_BEGIN_DECL + + +/** * Create a media splitter/combiner with the specified parameters. * A splitter/combiner splits a single stereo/multichannel audio frame into * multiple mono audio frames to each channel when put_frame() is called, @@ -107,6 +126,11 @@ pjmedia_splitcomb_create_rev_channel( pj_pool_t *pool, +PJ_END_DECL + +/** + * @} + */ #endif /* __PJMEDIA_SPLITCOMB_H__ */ diff --git a/pjmedia/include/pjmedia/wav_port.h b/pjmedia/include/pjmedia/wav_port.h index 6806f33f..99de617b 100644 --- a/pjmedia/include/pjmedia/wav_port.h +++ b/pjmedia/include/pjmedia/wav_port.h @@ -31,7 +31,7 @@ PJ_BEGIN_DECL /** - * @defgroup PJMEDIA_FILE_PLAY File Player + * @defgroup PJMEDIA_FILE_PLAY WAV File Player * @ingroup PJMEDIA_PORT * @brief WAV File Player * @{ @@ -77,18 +77,52 @@ PJ_DECL(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool, /** - * Set the play position of WAV player. + * Set the file play position of WAV player. * * @param port The file player port. - * @param samples Sample position (zero as start of file). + * @param offset Playback position in bytes, relative to the start of + * the payload. * * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) pjmedia_wav_player_port_set_pos( pjmedia_port *port, - pj_uint32_t samples ); + pj_uint32_t offset ); /** + * Get the file play position of WAV player. + * + * @param port The file player port. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port ); + + +/** + * Register a callback to be called when the file reading has reached the + * end of file. If the file is set to play repeatedly, then the callback + * will be called multiple times. Note that only one callback can be + * registered for each file port. + * + * @param port The file player port. + * @param user_data User data to be specified in the callback. Note that + * this overwrites the user data previously set when + * the file port is created. + * @param cb Callback to be called. If the callback returns non- + * PJ_SUCCESS, the playback will stop. Note that if + * application destroys the file port in the callback, + * it must return non-PJ_SUCCESS here. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) +pjmedia_wav_player_set_eof_cb( pjmedia_port *port, + void *user_data, + pj_status_t (*cb)(pjmedia_port *port, + void *usr_data)); + +/** * @} */ @@ -114,13 +148,13 @@ PJ_DECL(pj_status_t) pjmedia_wav_player_port_set_pos( pjmedia_port *port, * @param samples_per_frame Number of samples per frame. * @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. - * @param p_port Pointer to receive the file port instance. + * @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 port. + * @param p_port Pointer to receive the file port instance. * - * @return PJ_SUCCESS on success. + * @return PJ_SUCCESS on success. */ PJ_DECL(pj_status_t) pjmedia_wav_writer_port_create(pj_pool_t *pool, const char *filename, @@ -134,6 +168,44 @@ PJ_DECL(pj_status_t) pjmedia_wav_writer_port_create(pj_pool_t *pool, pjmedia_port **p_port ); +/** + * Get current writing position. Note that this does not necessarily match + * the size written to the file, since the WAV writer employs some internal + * buffering. Also the value reported here only indicates the payload size + * (it does not include the size of the WAV header), + * + * @param port The file writer port. + * + * @return Positive value to indicate the position (in bytes), + * or negative value containing the error code. + */ +PJ_DECL(pj_ssize_t) pjmedia_wav_writer_port_get_pos( pjmedia_port *port ); + + +/** + * Register the callback to be called when the file writing has reached + * certain size. Application can use this callback, for example, to limit + * the size of the output file. + * + * @param port The file writer port. + * @param pos The file position on which the callback will be called. + * @param user_data User data to be specified in the callback. Note that + * this overwrites the user data previously set when + * the file port is created. + * @param cb Callback to be called. If the callback returns non- + * PJ_SUCCESS, the writing will stop. Note that if + * application destroys the port in the callback, it must + * return non-PJ_SUCCESS here. + * + * @return PJ_SUCCESS on success. + */ +PJ_DECL(pj_status_t) +pjmedia_wav_writer_port_set_cb( pjmedia_port *port, + pj_size_t pos, + void *user_data, + pj_status_t (*cb)(pjmedia_port *port, + void *usr_data)); + /** * @} diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c index abf522b1..7c4ed922 100644 --- a/pjmedia/src/pjmedia/conference.c +++ b/pjmedia/src/pjmedia/conference.c @@ -1055,7 +1055,7 @@ static pj_status_t read_port( pjmedia_conf *conf, (int)cport->name.slen, cport->name.ptr, count)); - status = (cport->port->get_frame)(cport->port, &f); + status = pjmedia_port_get_frame(cport->port, &f); *type = f.type; @@ -1460,6 +1460,10 @@ static pj_status_t get_frame(pjmedia_port *this_port, */ continue; } + + /* Check that the port is not removed when we call get_frame() */ + if (conf->ports[i] == NULL) + continue; } /* If we need to adjust the RX level from this port, adjust the level diff --git a/pjmedia/src/pjmedia/wav_player.c b/pjmedia/src/pjmedia/wav_player.c index e7c3df40..8261f08a 100644 --- a/pjmedia/src/pjmedia/wav_player.c +++ b/pjmedia/src/pjmedia/wav_player.c @@ -30,7 +30,7 @@ #define THIS_FILE "wav_player.c" -#define SIGNATURE ('F'<<24|'P'<<16|'L'<<8|'Y') +#define SIGNATURE PJMEDIA_PORT_SIGNATURE('F', 'P', 'l', 'y') #define BYTES_PER_SAMPLE 2 @@ -65,6 +65,7 @@ struct file_port pj_off_t fpos; pj_oshandle_t fd; + pj_status_t (*cb)(pjmedia_port*, void*); }; @@ -116,9 +117,9 @@ static pj_status_t fill_buffer(struct file_port *fport) pj_ssize_t size; pj_status_t status; - if (fport->eof) { + /* Can't read file if EOF and loop flag is disabled */ + if (fport->eof) return PJ_EEOF; - } while (size_left > 0) { @@ -141,6 +142,27 @@ static pj_status_t fill_buffer(struct file_port *fport) * encountered EOF. Rewind the file. */ if (size < (pj_ssize_t)size_to_read) { + /* Call callback, if any. */ + if (fport->cb) { + PJ_LOG(5,(THIS_FILE, + "File port %.*s EOF, calling callback", + (int)fport->base.info.name.slen, + fport->base.info.name.ptr)); + + fport->eof = PJ_TRUE; + status = (*fport->cb)(&fport->base, fport->base.user_data); + if (status != PJ_SUCCESS) { + /* This will crash if file port is destroyed in the + * callback, that's why we set the eof flag before + * calling the callback: + fport->eof = PJ_TRUE; + */ + return status; + } + + fport->eof = PJ_FALSE; + } + if (fport->options & PJMEDIA_FILE_NO_LOOP) { PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, stopping..", (int)fport->base.info.name.slen, @@ -335,19 +357,23 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool, * Set position. */ PJ_DEF(pj_status_t) pjmedia_wav_player_port_set_pos(pjmedia_port *port, - pj_uint32_t samples ) + pj_uint32_t bytes ) { struct file_port *fport; - PJ_ASSERT_RETURN(port, PJ_EINVAL); + /* Sanity check */ + PJ_ASSERT_RETURN(port, -PJ_EINVAL); + + /* Check that this is really a player port */ + PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP); + fport = (struct file_port*) port; - PJ_ASSERT_RETURN(samples*BYTES_PER_SAMPLE < fport->fsize - - sizeof(pjmedia_wave_hdr), PJ_EINVAL); + PJ_ASSERT_RETURN(bytes < fport->fsize - sizeof(pjmedia_wave_hdr), + PJ_EINVAL); - fport->fpos = sizeof(struct pjmedia_wave_hdr) + - samples * BYTES_PER_SAMPLE; + fport->fpos = sizeof(struct pjmedia_wave_hdr) + bytes; pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET); fport->eof = PJ_FALSE; @@ -356,6 +382,58 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_set_pos(pjmedia_port *port, /* + * Get the file play position of WAV player. + */ +PJ_DEF(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port ) +{ + struct file_port *fport; + pj_size_t payload_pos; + + /* Sanity check */ + PJ_ASSERT_RETURN(port, -PJ_EINVAL); + + /* Check that this is really a player port */ + PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP); + + fport = (struct file_port*) port; + + payload_pos = (pj_size_t)(fport->fpos - sizeof(pjmedia_wave_hdr)); + if (payload_pos >= fport->bufsize) + return payload_pos - fport->bufsize + (fport->readpos - fport->buf); + else + return (fport->readpos - fport->buf) % payload_pos; +} + + + +/* + * Register a callback to be called when the file reading has reached the + * end of file. + */ +PJ_DEF(pj_status_t) +pjmedia_wav_player_set_eof_cb( pjmedia_port *port, + void *user_data, + pj_status_t (*cb)(pjmedia_port *port, + void *usr_data)) +{ + struct file_port *fport; + + /* Sanity check */ + PJ_ASSERT_RETURN(port, -PJ_EINVAL); + + /* Check that this is really a player port */ + PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP); + + fport = (struct file_port*) port; + + fport->base.user_data = user_data; + fport->cb = cb; + + return PJ_SUCCESS; +} + + +/* * Put frame to file. */ static pj_status_t file_put_frame(pjmedia_port *this_port, diff --git a/pjmedia/src/pjmedia/wav_writer.c b/pjmedia/src/pjmedia/wav_writer.c index 24816b27..a4b4f74b 100644 --- a/pjmedia/src/pjmedia/wav_writer.c +++ b/pjmedia/src/pjmedia/wav_writer.c @@ -28,7 +28,7 @@ #define THIS_FILE "wav_writer.c" -#define SIGNATURE ('F'<<24|'W'<<16|'R'<<8|'T') +#define SIGNATURE PJMEDIA_PORT_SIGNATURE('F', 'W', 'R', 'T') #define BYTES_PER_SAMPLE 2 @@ -38,8 +38,12 @@ struct file_port pj_size_t bufsize; char *buf; char *writepos; + pj_size_t total; pj_oshandle_t fd; + + pj_size_t cb_size; + pj_status_t (*cb)(pjmedia_port*, void*); }; static pj_status_t file_put_frame(pjmedia_port *this_port, @@ -177,6 +181,54 @@ PJ_DEF(pj_status_t) pjmedia_wav_writer_port_create( pj_pool_t *pool, } + +/* + * Get current writing position. + */ +PJ_DEF(pj_ssize_t) pjmedia_wav_writer_port_get_pos( pjmedia_port *port ) +{ + struct file_port *fport; + + /* Sanity check */ + PJ_ASSERT_RETURN(port, -PJ_EINVAL); + + /* Check that this is really a writer port */ + PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP); + + fport = (struct file_port*) port; + + return fport->total; +} + + +/* + * Register callback. + */ +PJ_DEF(pj_status_t) +pjmedia_wav_writer_port_set_cb( pjmedia_port *port, + pj_size_t pos, + void *user_data, + pj_status_t (*cb)(pjmedia_port *port, + void *usr_data)) +{ + struct file_port *fport; + + /* Sanity check */ + PJ_ASSERT_RETURN(port && cb, PJ_EINVAL); + + /* Check that this is really a writer port */ + PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVALIDOP); + + fport = (struct file_port*) port; + + fport->cb_size = pos; + fport->base.user_data = user_data; + fport->cb = cb; + + return PJ_SUCCESS; +} + + #if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0 static void swap_samples(pj_int16_t *samples, unsigned count) { @@ -234,6 +286,19 @@ static pj_status_t file_put_frame(pjmedia_port *this_port, pj_memcpy(fport->writepos, frame->buf, frame->size); fport->writepos += frame->size; + /* Increment total written, and check if we need to call callback */ + fport->total += frame->size; + if (fport->cb && fport->total >= fport->cb_size) { + pj_status_t (*cb)(pjmedia_port*, void*); + pj_status_t status; + + cb = fport->cb; + fport->cb = NULL; + + status = (*cb)(this_port, this_port->user_data); + return status; + } + return PJ_SUCCESS; } diff --git a/pjsip-apps/src/samples/confbench.c b/pjsip-apps/src/samples/confbench.c index 2dae32b7..26a0fac6 100644 --- a/pjsip-apps/src/samples/confbench.c +++ b/pjsip-apps/src/samples/confbench.c @@ -17,11 +17,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* + +/** + * \page page_pjmedia_samples_confbench_c Samples: Benchmarking Conference Bridge + * * Benchmarking pjmedia (conference bridge+resample). For my use only, * and it only works in Win32. + * + * This file is pjsip-apps/src/samples/confbench.c + * + * \includelineno confbench.c */ + #include <pjmedia.h> #include <pjlib-util.h> /* pj_getopt */ #include <pjlib.h> @@ -38,8 +46,8 @@ * HAS_RESAMPLE will activate resampling on about half * the port. */ -#define TEST_SET SMALL_SET -#define HAS_RESAMPLE 1 +#define TEST_SET LARGE_SET +#define HAS_RESAMPLE 0 #define SMALL_SET 16 @@ -265,7 +273,10 @@ int main() return 1; } + printf("Resampling is %s\n", (HAS_RESAMPLE?"active":"disabled")); + /* Create Null ports */ + printf("Creating %d null ports..\n", NULL_COUNT); for (i=0; i<NULL_COUNT; ++i) { status = pjmedia_null_port_create(pool, CLOCK_RATE, 1, SAMPLES_PER_FRAME*2, 16, &nulls[i]); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); @@ -275,6 +286,7 @@ int main() } /* Create sine ports. */ + printf("Creating %d sine generator ports..\n", SINE_COUNT); for (i=0; i<SINE_COUNT; ++i) { unsigned j, slot; @@ -304,6 +316,7 @@ int main() } /* Create idle ports */ + printf("Creating %d idle ports..\n", IDLE_COUNT); for (i=0; i<IDLE_COUNT; ++i) { pjmedia_port *dummy; status = pjmedia_null_port_create(pool, CLOCK_RATE, 1, SAMPLES_PER_FRAME, 16, &dummy); diff --git a/pjsip-apps/src/samples/confsample.c b/pjsip-apps/src/samples/confsample.c index 7ae80cdc..d87a916a 100644 --- a/pjsip-apps/src/samples/confsample.c +++ b/pjsip-apps/src/samples/confsample.c @@ -26,6 +26,18 @@ #include "util.h" +/** + * \page page_pjmedia_samples_confsample_c Samples: Using Conference Bridge + * + * Sample to mix multiple files in the conference bridge and play the + * result to sound device. + * + * This file is pjsip-apps/src/samples/confsample.c + * + * \includelineno confsample.c + */ + + /* For logging purpose. */ #define THIS_FILE "confsample.c" diff --git a/pjsip-apps/src/samples/level.c b/pjsip-apps/src/samples/level.c index e2169841..dcf6499d 100644 --- a/pjsip-apps/src/samples/level.c +++ b/pjsip-apps/src/samples/level.c @@ -17,6 +17,19 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * \page page_pjmedia_samples_level_c Samples: Reading from WAV File + * + * This is a very simple example to use the @ref PJMEDIA_FILE_PLAY, to + * directly read the samples from the file. + * + * This file is pjsip-apps/src/samples/level.c + * + * \includelineno level.c + */ + + static const char *desc = " FILE: \n" " level.c \n" diff --git a/pjsip-apps/src/samples/playfile.c b/pjsip-apps/src/samples/playfile.c index 5b26cd57..754304b3 100644 --- a/pjsip-apps/src/samples/playfile.c +++ b/pjsip-apps/src/samples/playfile.c @@ -26,6 +26,22 @@ #include "util.h" +/** + * \page page_pjmedia_samples_playfile_c Samples: Playing WAV File to Sound Device + * + * This is a very simple example to use the @ref PJMEDIA_FILE_PLAY and + * @ref PJMED_SND_PORT. In this example, we open both the file and sound + * device, and connect the two of them, and voila! Sound will be playing + * the contents of the file. + * + * @see page_pjmedia_samples_recfile_c + * + * This file is pjsip-apps/src/samples/playfile.c + * + * \includelineno playfile.c + */ + + /* * playfile.c * diff --git a/pjsip-apps/src/samples/playsine.c b/pjsip-apps/src/samples/playsine.c index 931f9123..ae4bec8c 100644 --- a/pjsip-apps/src/samples/playsine.c +++ b/pjsip-apps/src/samples/playsine.c @@ -17,6 +17,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * \page page_pjmedia_samples_playsine_c Samples: Using Custom Ports (Sine Wave Generator) + * + * This example demonstrate how to create a custom media port (in this case, a + * sine wave generator) and connect it to the sound device. + * + * This file is pjsip-apps/src/samples/playsine.c + * + * \includelineno playsine.c + */ + /* * playsine.c * diff --git a/pjsip-apps/src/samples/recfile.c b/pjsip-apps/src/samples/recfile.c index 2236dcad..29aa8324 100644 --- a/pjsip-apps/src/samples/recfile.c +++ b/pjsip-apps/src/samples/recfile.c @@ -17,6 +17,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/** + * \page page_pjmedia_samples_recfile_c Samples: Capturing Audio to WAV File + * + * In this example, we capture audio from the sound device and save it to + * WAVE file. + * + * @see page_pjmedia_samples_playfile_c + * + * This file is pjsip-apps/src/samples/recfile.c + * + * \includelineno recfile.c + */ #include <pjmedia.h> #include <pjlib.h> @@ -26,6 +38,7 @@ /* For logging purpose. */ #define THIS_FILE "recfile.c" + /* Configs */ #define CLOCK_RATE 44100 #define SAMPLES_PER_FRAME (CLOCK_RATE * 20 / 1000) diff --git a/pjsip-apps/src/samples/resampleplay.c b/pjsip-apps/src/samples/resampleplay.c index f8768591..9c7b2f1f 100644 --- a/pjsip-apps/src/samples/resampleplay.c +++ b/pjsip-apps/src/samples/resampleplay.c @@ -16,6 +16,18 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/** + * \page page_pjmedia_samples_resampleplay_c Samples: Using Resample Port + * + * This example demonstrates how to use @ref PJMEDIA_RESAMPLE_PORT to + * change the sampling rate of the media streams. + * + * This file is pjsip-apps/src/samples/resampleplay.c + * + * \includelineno resampleplay.c + */ + #include <pjmedia.h> #include <pjlib-util.h> #include <pjlib.h> diff --git a/pjsip-apps/src/samples/siprtp.c b/pjsip-apps/src/samples/siprtp.c index 42709660..4ffe0123 100644 --- a/pjsip-apps/src/samples/siprtp.c +++ b/pjsip-apps/src/samples/siprtp.c @@ -20,6 +20,7 @@ + /* Usage */ static const char *USAGE = " PURPOSE: \n" diff --git a/pjsip-apps/src/samples/sipstateless.c b/pjsip-apps/src/samples/sipstateless.c index c3cfe071..4c8354c5 100644 --- a/pjsip-apps/src/samples/sipstateless.c +++ b/pjsip-apps/src/samples/sipstateless.c @@ -103,20 +103,13 @@ int main() /* Create global endpoint: */ { - const pj_str_t *hostname; - const char *endpt_name; - /* Endpoint MUST be assigned a globally unique name. - * The name will be used as the hostname in Warning header. + * Ideally we should put hostname or public IP address, but + * we'll just use an arbitrary name here. */ - /* For this implementation, we'll use hostname for simplicity */ - hostname = pj_gethostname(); - endpt_name = hostname->ptr; - /* Create the endpoint: */ - - status = pjsip_endpt_create(&cp.factory, endpt_name, + status = pjsip_endpt_create(&cp.factory, "sipstateless", &sip_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } diff --git a/pjsip-apps/src/samples/sndtest.c b/pjsip-apps/src/samples/sndtest.c index 2c469775..c2b75b99 100644 --- a/pjsip-apps/src/samples/sndtest.c +++ b/pjsip-apps/src/samples/sndtest.c @@ -17,6 +17,21 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/** + * \page page_pjmedia_samples_sndtest_c Samples: Sound Card Benchmark + * + * This example can be used to benchmark the quality of the sound card + * installed in the system. At the end of the test, it will report + * the jitter and clock drifts of the device. + * + * This file is pjsip-apps/src/samples/sndtest.c + * + * Screenshots on WinXP: \image html sndtest.jpg + * + * \includelineno sndtest.c + */ + + #include <pjmedia.h> #include <pjlib.h> #include <pjlib-util.h> diff --git a/pjsip-apps/src/samples/streamutil.c b/pjsip-apps/src/samples/streamutil.c index 29ba520e..4609df0b 100644 --- a/pjsip-apps/src/samples/streamutil.c +++ b/pjsip-apps/src/samples/streamutil.c @@ -18,6 +18,18 @@ */ +/** + * \page page_pjmedia_samples_streamutil_c Samples: Remote Streaming + * + * This example mainly demonstrates how to stream media file to remote + * peer using RTP. + * + * This file is pjsip-apps/src/samples/streamutil.c + * + * \includelineno streamutil.c + */ + + static const char *desc = " streamutil \n" " \n" diff --git a/pjsip/docs/doxygen.cfg b/pjsip/docs/doxygen.cfg index 3edc5bfc..59d6e659 100644 --- a/pjsip/docs/doxygen.cfg +++ b/pjsip/docs/doxygen.cfg @@ -384,7 +384,7 @@ EXCLUDE_PATTERNS = # directories that contain example code fragments that are included (see
# the \include command).
-EXAMPLE_PATH =
+EXAMPLE_PATH = ../pjsip-apps/src/samples ../pjsip-apps/src/pjsua
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
@@ -404,7 +404,7 @@ EXAMPLE_RECURSIVE = NO # directories that contain image that are included in the documentation (see
# the \image command).
-IMAGE_PATH =
+IMAGE_PATH = docs ../pjmedia/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
diff --git a/pjsip/docs/doxygen.h b/pjsip/docs/doxygen.h index d13ae200..604284f6 100644 --- a/pjsip/docs/doxygen.h +++ b/pjsip/docs/doxygen.h @@ -181,3 +181,96 @@ */ +/** + @page page_pjsip_samples PJSIP Samples + + I wish I could write more samples, but for now here are some samples or + working applications that are available from the source tree: + + - @ref page_pjsip_sample_sipstateless_c\n + This is about the simplest SIP application with PJSIP, all it does is + respond all incoming requests with 501 (Not Implemented) response + statelessly. + + - @ref page_pjsip_sample_simple_ua_c\n + This is a very simple SIP User Agent application that only use PJSIP + (without PJSIP-UA). It's able to make and receive call, and play + media to the sound device. + + - @ref page_pjsip_samples_pjsua\n + This is the reference implementation for PJSIP and PJMEDIA. + PJSUA is a console based application, designed to be simple enough + to be readble, but powerful enough to demonstrate all features + available in PJSIP and PJMEDIA.\n + Screenshot on WinXP: \image html pjsua.jpg "pjsua on WinXP" + + - @ref page_pjmedia_samples_siprtp_c\n + This is a useful program (integrated with PJSIP) to actively measure + the network quality/impairment parameters by making one or more SIP + calls (or receiving one or more SIP calls) and display the network + impairment of each stream direction at the end of the call. + The program is able to measure network quality parameters such as + jitter, packet lost/reorder/duplicate, round trip time, etc.\n + Note that the remote peer MUST support RTCP so that network quality + of each direction can be calculated. Using siprtp for both endpoints + is recommended.\n + Screenshots on WinXP: \image html siprtp.jpg "siprtp screenshot on WinXP" + + */ + +/** + * \page page_pjsip_samples_pjsua PJSUA + * + * This is the reference implementation for PJSIP and PJMEDIA. + * PJSUA is a console based application, designed to be simple enough + * to be readble, but powerful enough to demonstrate all features + * available in PJSIP and PJMEDIA. + * + * This file is pjsip-apps/src/pjsua/pjsua_app.c + * + * Screenshot on WinXP: \image html pjsua.jpg "pjsua on WinXP" + * + * \includelineno pjsua_app.c + */ + +/** + * \page page_pjsip_sample_simple_ua_c Samples: Simple UA + * + * This is a very simple SIP User Agent application that only use PJSIP + * (without PJSIP-UA). It's able to make and receive call, and play + * media to the sound device. + * + * \includelineno simpleua.c + */ + +/** + * \page page_pjsip_sample_sipstateless_c Samples: Stateless SIP Endpoint + * + * This is about the simplest SIP application with PJSIP, all it does is + * respond all incoming requests with 501 (Not Implemented) response + * statelessly. + * + * \includelineno sipstateless.c + */ + +/** + * \page page_pjmedia_samples_siprtp_c Samples: Using SIP and Custom RTP/RTCP to Monitor Quality + * + * This source is an example to demonstrate using SIP and RTP/RTCP framework + * to measure the network quality/impairment from the SIP call. This + * program can be used to make calls or to receive calls from other + * SIP endpoint (or other siprtp program), and to display the media + * quality statistics at the end of the call. + * + * Note that the remote peer must support RTCP. + * + * The layout of the program has been designed so that custom reporting + * can be generated instead of plain human readable text. + * + * The source code of the file is pjsip-apps/src/samples/siprtp.c + * + * Screenshots on WinXP: \image html siprtp.jpg + * + * \includelineno siprtp.c + */ + diff --git a/pjsip/docs/pjsua.jpg b/pjsip/docs/pjsua.jpg Binary files differnew file mode 100644 index 00000000..479567bb --- /dev/null +++ b/pjsip/docs/pjsua.jpg |