= PJSIP FAQ = Here you can find answers to some of the most frequently asked questions about PJSIP. If you have a question not answered on this page, you can ask it on the [http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org PJSIP mailing list]. ---- [[PageOutline(2-3,,inline)]] ---- == General Questions == #general === Where can I find the latest release of PJSIP? === #latest The latest PJSIP is always the SVN trunk version. Please find the information on how to retrieve PJSIP from SVN in the [http://www.pjsip.org/download.htm PJSIP Download] and [wiki:Getting-Started Getting Started] page. === Where and how can I find documentation about PJSIP? === #doc These are the places to look for documentations: '''This FAQ''' :: Many questions are discussed in this FAQ, your questions may have been answered here. '''The website ([http://www.pjsip.org/docs.htm])''' :: This is the place for the API reference documentation, which is kept up to date with the latest release. It also contains technical articles such as footprint and performance experimentation, although these are somewhat older documentation. These days we normally put experimentation results in the Trac Wiki page (below). '''The Trac Wiki page ([. http://trac.pjsip.org/repos/wiki])''' :: This contains tutorials, how-tos, troubleshooting guides, and technical articles, and it is more up to date than the pjsip website. '''The mailing list archive ([http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/])''' :: The current list archive has been running for two years (unfortunately we lost the older archive), and there have been thousands of discussions. There are two ways to search for documentation: - for website and mailing list, use Google site search (mind you the website and list archive have different domain name, "www" vs "lists"). - for Trac, search using the Trac search facility (on the top right corner of this page). Our Trac site is not search engine indexable so it won't be picked up by search engines if you search it directly with Google. === If PJSIP is said to be small footprint, then why the source is so big? === #src-large It is common in all projects to have source distribution that is larger than the resulting build. This is because source distribution contains other things such as documentations and scripts. The source tarball of PJSIP v0.7 is significantly larger than v0.5 because in v0.7 we include third party libraries in their original form of distribution, so that they get proper attribution and for easier update, unlike in v.0.5 where we just picked the source files that we like and included them in PJSIP. === How can I use PJSIP in my own C program? === #use_own First start with this: {{{ #include int main() { puts("Hello world!"); return; } }}} Then read on to the next topic below. === I have downloaded PJSIP source codes, now what next? === #do First you'll need to build the sources, by following the instructions in [wiki:Getting-Started Getting Started] page. Then you can get yourself familiar with PJSIP features by running [http://www.pjsip.org/pjsua.htm pjsua] application. ''pjsua'' is the reference implementation of PJSIP and PJSUA-LIB. Although it doesn't have all the PJSIP features, it contains most of them, so it's quite useful. Please find ''pjsua'' documentation in [http://www.pjsip.org/pjsua.htm pjsua Manual] page. It is also good to get familiar with ''pjsua'' since if you'll ever get any problems with PJSIP, most likely we will ask to reproduce it with ''pjsua'', to determine whether the problem is PJSIP problem or the problem with the implementation. So please try this out. You may even be able to impress your mates by doing SIP calls, conference, IM, and presence from a command line application! Next, I assume that you want to develop some sort of SIP applications, yes? At this point, you'll need to decide which API abstractions to use. If building client applications, [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA-LIB API] may be the better option to use, since this library has easy to use but yet powerful API. On the other hand, since it's a high level API, it may not provide all the flexibilities that are required by the application. Nor the [#pjsua-lib-perf performance], perhaps. Or it may just contain too many features! In this case, perhaps using [http://www.pjsip.org/pjsip/docs/html/index.htm PJSIP] and [http://www.pjsip.org/pjmedia/docs/html/index.htm PJMEDIA] directly would be a better option. They will be "slightly" more difficult to use, but they will provide the utmost flexibility, performance, and size. Then prepare the application project, by following the instructions in [http://www.pjsip.org/using.htm#using Getting Started | Using PJSIP for Applications] documentation. The details would depend on what platform you're working on. Then fill up the application features, by following the [http://www.pjsip.org/docs.htm Documentation] or by looking at [http://www.pjsip.org/pjsip/docs/html/page_pjsip_samples.htm PJSIP samples] or [http://www.pjsip.org/pjmedia/docs/html/page_pjmedia_samples.htm PJMEDIA samples]. In case you're using PJSIP and PJMEDIA directly, you can have a look at PJSUA-LIB source code for reference. If you'll ever get into any troubles, we're ready to help in [http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org PJSIP mailing list]. So good luck then! === It's an assertion, and not a crash, dammit! :) === #assert Very often we received a report that PJSIP crashes, while actually it's ''just'' an assertion. This makes a big difference for us in terms of troubleshooting, since a crash means fatal bug, while an assertion just serves as a warning thus it is not as fatal. In PJSIP, we use assertion as means to warn developers that something unexpected has happened. This may be due to some wrong assumption being made during development, some invalid values being used, or some other mistakes done by the developer. The developer can be you or me of course. The conventions that we use consistently are: * assertion should only be raised for unexpected errors generated locally. For errors coming from external sources (such as a malformed SIP message received from remote), it must not raise assertion, and rather a usual error handling must be performed. * assertion must not replace a proper error handling, thus when assertion is disabled, the program should fallback to using error handling as usual. We use [http://www.pjsip.org/pjlib/docs/html/group__pj__assert.htm#gc98bea768b573f53432076a387864fb3 PJ_ASSERT_RETURN()] macro a lot. The idea of this macro is to raise an assertion during development so that any problems can be found and fixed early, and on the production release where the assertion is disabled, the macro will revert to error handling so that the application will not terminate unexpectedly with ''Assertion failure'' error. So yes, '''you should disable assertion on the release version''' of the software. This is another convention that we use. In conclusion, please distinguish between assertion and crash when reporting a problem so that we can give the report the appropriate attention. === I still think there is a bug. Or at least a problem. Where can I report it? === #bug-reports You can report issues and problem to our [http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org mailing list]. ---- == Compatibility == #compatibility === What SIP products are compatible with PJSIP? === #compatible Basically as PJSIP is based on IETF standards (SIP, RTP/RTCP, STUN, ICE, etc.), so it should be compatible with other standard based products. We and the community are constantly using PJSIP with other open source products such as: - [http://www.iptel.org SER], - [http://www.openser.org OpenSER], and - [http://www.asterisk.org Asterisk]. We have also heard people successfully done interoperability tests with commercial SIP servers or phones, and we try to attend [http://www.sipit.net Sipit] regularly. But we don't specificly maintain list of these products, for now. Basically the principle stays the same, as long as they follow the standards, we are confident that PJSIP should be able to communicate with them. ---- == Licensing Questions == #licensing === Why is PJSIP licensed as GPL, and not (LGPL|MPL|BSD|choose your OSS license here)? === #non-gnu Basically we agree with FSF on this issue. Quoting the [http://www.gnu.org/licenses/gpl-faq.html GPL FAQ]: [http://www.gnu.org/licenses/gpl-faq.html#WhyUseGPL Why should I use the GNU GPL rather than other free software licenses?] ''Using the GNU GPL will require that all the [http://www.gnu.org/philosophy/pragmatic.html released improved versions] be free software. This means you can avoid the risk of having to compete with a proprietary modified version of your own work.'' We don't want people to take PJSIP, mess it up (erm, improve it), and keep the improvements as proprietary code. On the contrary, we want everybody to enjoy PJSIP and all its improvements, and the only way to make sure of this is by releasing PJSIP as GPL. Sure this still leaves some debate over why not use, say LGPL, but I guess this page is probably too short to cover that. Our stand on LGPL is explained much better [http://www.fsf.org/licensing/licenses/why-not-lgpl.html here]. === What about the "viral" nature of the GPL? === #gpl People often think that using GPL-ed software means that other software linked with the GPL software have to be GPL too, hence GPL is considered as viral. '''That is not exactly true'''. Don't forget that GPL '''is compatible''' with many other free software licenses, including: - Public domain - [http://www.gnu.org/licenses/info/Sleepycat.html Berkeley Database License], - [http://www.gnu.org/licenses/ecos-license.html eCos license version 2.0], - [http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 Modified BSD license] (the original BSD license modified by removal of the advertising clause, sometimes is referred to as the 3-clause BSD license), - [http://www.jclark.com/xml/copying.txt Expat License], - [http://www.freebsd.org/copyright/freebsd-license.html FreeBSD license], - [http://www.xfree86.org/3.3.6/COPYRIGHT2.html#3 X11 License], and of course, - [http://www.gnu.org/licenses/lgpl.html GNU LGPL]. And don't forget that the PJSIP license is GPLv2 '''or later''', which means one can use PJSIP under GPLv3, which is compatible with even more licenses such as: - [http://www.apache.org/licenses/LICENSE-2.0 Apache License Version 2.0] and - [http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx Microsoft Public License (Ms-PL)]. For more complete list of licenses that are compatible with GPL, please see http://www.gnu.org/licenses/license-list.html. In addition, we specifically allow linking PJSIP with some open source third party libraries, as they are listed in [http://www.pjsip.org/licensing.htm Third Party Software] page. === Can I develop closed source products with PJSIP? === #proprietary It depends. We use the standard GPL v2 or later for PJSIP, and GPL does allow using GPL-ed code for closed source development, '''as long as the resulting product is not redistributed''' (for example, it is only used for internal purpose). Please see [http://www.gnu.org/licenses/gpl-faq.html GPL FAQ] for more information about what can/can't be done with GPL software. Alternatively, we can discuss alternative licensing for PJSIP, please contact support@pjsip.org for details. === What are the licensing requirements of the third party libraries used by PJSIP? === #third-party Apart from the licensing requirements of PJSIP, please be aware that some third party libraries used by PJSIP put additional requirements to the end product (that is, the application using PJSIP), please check [http://www.pjsip.org/licensing.htm#third Third Party Software] for detail info. ---- == Build and Installation Issues == === I'm having problem building PJSIP, please help! === #build-problems Please check the [wiki:Getting-Started Getting Started] page. === I'm getting "Unable to open DSound.h error", please help! === #dsound You should really check the [wiki:Getting-Started Getting Started] page first. Please check the [wiki:Getting-Started Getting Started] page. === How do I build the libraries as Dynamic Link Library (DLL)? === #dll In general, we don't provide DLL projects for Windows, but please see [http://www.pjsip.org/pjlib/docs/html/group__pj__dll__target.htm Building Dynamic Link Libraries] page in PJLIB documentation on how to build these DLL yourself. === Configuration macros are not set properly by configure script === #crlf Q: After running {{{./configure}}} script successfully, {{{make}}} returns this error: {{{ .. ../../pjlib/include/pj/config.h:1006:4: error: #error "PJ_HAS_HIGH_RES_TIMER is not defined!" ../../pjlib/include/pj/config.h:1022:4: error: #error "PJ_EMULATE_RWMUTEX should be defined in compat/os_xx.h" .. }}} And upon inspecting {{{pjlib/include/pj/compat/os_auto.h}}}, all macros are undefined: {{{ ... /* Canonical OS name */ /* #undef PJ_OS_NAME */ /* Legacy macros */ /* #undef PJ_WIN32 */ /* #undef PJ_WIN32_WINNT */ ... }}} However {{{config.log}}} shows that these macros have been resolved properly: {{{ .. ## ----------- ## ## confdefs.h. ## ## ----------- ## #define HAVE_INTTYPES_H 1 #define HAVE_LIBM 1 #define HAVE_LIBNSL 1 #define HAVE_LIBPTHREAD 1 }}} A: According to this discussion entitled [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-May/002915.html Error in configuring SVN version, on Linux, i686] on pjsip mailing list, this was caused by incorrect CRLF line endings in the {{{pjlib/include/pj/compat/os_auto.h.in}}} file, causing {{{sed}}} to fail. If you're working on Linux, make sure that you use the {{{.tar.gz}}} tarball rather than the {{{.zip}}} file since both have different CRLF formatting. Also don't copy files which are checked out on Windows to Linux, since files checked out on Windows will have CRLF endings. And be careful when transferring/editing source files between your Linux and a Windows machine, when you edit a file on Windows the CRLF endings may be set to CRLF too. ---- == Integration Issues == === How can I integrate third party media stack with PJSIP? === #third-party-media Please see this article: '''[wiki:3rd_Party_Media Integrating Third Party Media Stack with PJSIP]''' === What platforms are PJSIP known to run on? === #platforms PJSIP runs on many platforms, embedded or non-embedded. Please see the platforms list that it currently supports in [http://www.pjsip.org/sip_media_features.htm#platforms Platform features] page. Apart from the platforms that we maintain ourselves, the community have also been constantly finding new platforms that PJSIP can run on, for example on [http://libw11.free.fr/ Nintendo DS] (a cool project by Samuel Vinson), and also on various platforms based on uC-Linux and ARM processor. === How can I port PJSIP to platform XYZ? === #porting PJSIP has been designed for ultra-portability, and we have ported PJSIP to exotic platform such as Symbian (long time ago, PJSIP has also been ported to Linux kernel). People even have ported PJSIP to even more exotic platforms such as [http://libw11.free.fr/ Nintendo DS] (ported by Samuel Vinson) and Texas Instrument (TI) DSP. So there is a good chance that PJSIP will be ''port''-able to your platform. Please start from the [http://www.pjsip.org/porting.htm Porting] page. For additional information, there is also information on porting [http://www.pjsip.org/sip_symbian.htm PJSIP to Symbian], to emphasize that even on difficult platform like this, PJSIP is still ''port''-able. === How can I implement my own audio device? === #ext-audio There are two steps required: 1. develop your audio device implementation. You can use the {{{nullsound.c}}} as your template, and existing sound device backend sources as reference. 1. integrate your impplementation into the build system, by following [wiki:External_Sound_Device this guideline]. ---- == Audio Questions == #media === I'm having problems with no/poor audio (quality), please help! === #audio-problem We have created a Wiki page dedicated for troubleshooting all sorts of audio problems, please follow the instructions in [wiki:sound-problems Troubleshooting Sound Problems wiki]. If this does not solve your problem, please consult the [http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org PJSIP mailing list]. === I'm having problems with echo, please help === #echo Please see above. === How can I reduce audio latency? === #audio-latency The end to end audio latency consists of the following components: 1. The latency of the sound capture. 1. Codec latency on both sender and receiver. 1. Other algorithmic latency (such as AEC or sample rate conversion). 1. Network latency. 1. Jitter buffering on the receiver end. 1. The latency of the sound playback. On typical PC, normally it's the sound device and jitter buffer that contribute the most latency, so this article will try to present how to optimize these settings. Codec latency is determined by the codec algorithm and its {{{ptime}}}, but normally it shouldn't add too much latency; maybe around 20 to 30 ms. The default resampling algorithm in PJMEDIA adds about 5 ms latency. I have no idea about AEC latency. Network latency, well, we can't do anything about it. ==== Choosing lower audio frame length ==== Older pjsip:: Ticket #393 (release 0.7.1) added a new media setting {{{pjsua_media_config.audio_frame_ptime}}}, or in older PJSUA-LIB, this setting is hard-coded in {{{PTIME}}} macro in {{{pjsua_media.c}}}. This setting specifies the length of audio frame in milliseconds, to be set to both the sound device and to the conference bridge. The previous default value is 20 milliseconds, while the default value is now set to 10 milliseconds. Changing this value from 20 to 10 milliseconds will reduce sound device latency by about 100 milliseconds and end-to-end audio latency by about 200 milliseconds. pjsip version 0.9 and later:: The default value is now 20ms, and changing this to 10ms will only reduce latency slightly. ==== Choose PJMEDIA_SOUND_BUFFER_COUNT carefully ==== Older pjsip: :: The {{{PJMEDIA_SOUND_BUFFER_COUNT}}} in {{{pjmedia/config.h}}} specifies the number of audio frames in the conference bridge buffer. Larger number is better for sound stability and to accommodate sound devices that are unable to send frames in timely manner, however it would probably cause more audio delay. The default value was 16, and this has been changed to 6 by ticket #394 (release 0.7.1). pjsip version 0.9 and later: :: PJSIP now uses adaptive delay buffer to automatically learn the amount of buffers required to handle the burst. The semantic of PJMEDIA_SOUND_BUFFER_COUNT has been changed, and rather now it means the maximum amount of buffering that will be handled by the delay buffer. Lowering the value will not affect latency, and may cause unnecessary WSOLA processing (to discard the excessive frames because the buffer is full) and may even produce audio impairments, hence it's no longer recommended. ==== Optimizing Sound Device Latency ==== Older pjsip: :: On Windows with !PortAudio backend (the default sound driver backend), with the default setting !DirectSound does have lower latency than WMME, but !DirectSound has more erratic timing. This bad timing causes additional delay in the processing of packets in the jitter buffer; there can be up to 150ms delay between packet arrival time and the time when the frame is actually picked up from the jitter buffer, regardless of jitter buffer setting. Release 0.7.1 has been tuned to provide better latency, with providing these settings: - ticket #384 gives the ability for application to choose !DirectSound over WMME. Default is no - ticket #395 adds a configuration to control the maximum buffer latency for WMME, with default value is 60 (milliseconds). For similar setting for !DirectSound, application needs to set {{{PA_MIN_LATENCY_MSEC}}} environment variable. With default WMME backend and 60 milliseconds buffering, application should have much better latency than with using !DirectSound. pjsip version 0.9 and later: :: The maximum buffer latency setting above has been deprecated, and instead we introduced two pjmedia settings to control the sound device buffer size/latency value: {{{PJMEDIA_SND_DEFAULT_REC_LATENCY}}} and {{{PJMEDIA_SND_DEFAULT_PLAY_LATENCY}}}. The default values for both settings are 100 ms. Application can also change the latency at run-time by calling {{{pjmedia_snd_set_latency()}}} '''before''' opening the sound device. Setting the latency to lower value will affect the audio stability (it will make it more sensitive to CPU disruptions), so choose the value carefully. ==== Optimizing Jitter Buffer Latency ==== Older pjsip: :: The jitter buffer parameters are specified in {{{pjsua_media_config}}}, with the relevant fields are: - '''jb_min_pre''' - Jitter buffer minimum prefetch delay in msec. With the default settings, it will use the hard-coded value in {{{stream.c}}}, that is '''60''' ms. - '''jb_max_pre''' - Jitter buffer maximum prefetch delay in msec. With the default settings, it will use the hard-coded value in {{{stream.c}}}, that is '''240''' ms. - '''jb_max''' - Set maximum delay that can be accomodated by the jitter buffer msec. The default value is also hard-coded in {{{stream.c}}}, that is '''360''' ms. pjsip version 0.9 and later: :: The jitter buffer implementation has been modified and it should reduce latency significantly. === How to run PJSUA without sound device? === #no-snd-dev Some PJSUA-LIB based applications do not need to interact with local sound device, thus do not need to have sound device in the deployed machine. PJSUA-LIB indeed supports running the media without sound device. With ''pjsua'' application, you can run ''pjsua'' without sound device with {{{--null-audio}}} option. === How can I adjust the audio volume level? === #audio-volume The easiest is to adjust the audio level in the conference bridge, using: - [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONF.htm#g8895228fdc9b7d6892320aa03b198574 pjmedia_conf_adjust_rx_level()] and [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONF.htm#gff0b554ee974c7905071f1051eeb4479 pjmedia_conf_adjust_tx_level()], if you use PJMEDIA directly, or - [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#gac62b6ef2ec5dd2f8717809548201e89 pjsua_conf_adjust_rx_level()] and [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#gd828a91a6ee5d361ecb07fa818e17e41 pjsua_conf_adjust_tx_level()] if you use PJSUA-API. Note that the two different APIs have different level adjustment value; PJMEDIA expects the value in integer, while PJSUA expects the value in floating point. Please see the API documentation for the details. Another way to manage the audio level is to use the operating system specific API to adjust the audio device level directly. Currently PJMEDIA does not provide portable APIs to interact with audio device level, so please see the operating system SDK documentation for information on how to achieve this. === I didn't hear ringing tones when I make a call, why? === #ringtone older pjsip: :: ''pjsua'' does not play any ring tones when the call gets 180/Ringing, since it's just a simple application for demonstration purpose. When you're building your own application, you can add this feature yourself. You can play a ringing tone by using the tone generator as described above (but connecting the tone generator to the sound device instead of to the call), or you can play your own WAV file instead. pjsip version 0.9 and later: :: pjsua now supports generating local ringback tones! === Outgoing RTP transmissions are not timed equally/properly. Why? === #tx-timing In PJMEDIA default setup, media flow is normally triggered by the ''clock'' from the audio device. We made this kind of design to ensure that the audio device always gets fed whenever it needs to be fed, and also since this design would work best for DSP devices, where audio flow would be triggered by some kind of (soft) IRQs thus it should provide the best timing source for audio flow (and without needing to have multi-threading capability). Unfortunately, not all audio devices provide good timing. Especially in PC world, and also with some uC-Linux based development boards that only support OSS, it is very common to have sound cards that can't provide reliable timing. On these platforms, audio frames will come in burst rather than one by one and spaced equally. So with 20ms ''ptime'' for example, rather than having one frame every 20ms, these devices would give PJMEDIA three or four frames every 60ms or 80ms. Since RTP packets are transmitted as soon as audio frame is available from the sound card, this would cause PJMEDIA to transmit RTP packets at (what looks like) irregular interval. In my opinion, this should be fine, as the remote endpoint should be able to accommodate this with its ''jitter buffer''. If you don't like this, and rather want PJMEDIA to transmit RTP packets at good interval, you can install a [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__MASTER__PORT.htm master clock port] between sound device and conference bridge, so that the master port will drive the media clock instead. A master clock port uses an internal thread to drive the media flow, so it should provide better timing on most platforms. The steps to install master port between sound device and conference bridge are as follows: 1. Create a [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__SPLITCOMB.htm splitter/combiner (splitcomb) port]. 1. Create a reverse phase port on the splitcomb ([http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__SPLITCOMB.htm#gc59338fd9d471a14c06b0f51c2290b68 pjmedia_splitcomb_create_rev_channel()]). 1. Create the [http://www.pjsip.org/pjmedia/docs/html/group__PJMED__SND__PORT.htm sound device port] as usual. 1. Connect the sound device port to the splitcomb (use [http://www.pjsip.org/pjmedia/docs/html/group__PJMED__SND__PORT.htm#g046156b765a34e6c640b0534e6b21f9c pjmedia_snd_port_connect()]). 1. Create a [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__MASTER__PORT.htm master clock port], and specify the splitcomb's reverse channel as the ''upstream'' port, and the [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONF.htm conference bridge] as the ''downstream'' port. 1. Start the master port. For example, normally we ''connect'' the sound device to the conference bridge (the default setup in pjsua-lib) with the code below: {{{ #!c void connect_conf_bridge_to_snd_dev(pj_pool_t *pool, pjmedia_port *conf) { pjmedia_snd_port *snd; pjmedia_snd_port_create(..., &snd); pjmedia_snd_port_connect(snd, conf); } }}} The change required to install master clock between sound device and conference bridge would be something like this: {{{ #!c void connect_conf_bridge_to_snd_dev2(pj_pool_t *pool, pjmedia_port *conf) { pjmedia_port *splitcomb, *rev; pjmedia_snd_port *snd; pjmedia_master_port *m; pjmedia_splitcomb_create(pool, CLOCK_RATE, 1, SAMPLES_PER_FRAME, BITS, 0, &splitcomb); pjmedia_splitcomb_create_rev_channel(pool, splitcomb, 0, 0, &rev); pjmedia_snd_port_create(..., &snd); pjmedia_snd_port_connect(snd, splitcomb); pjmedia_master_port_create(pool, rev, conf, 0, &m); pjmedia_master_port_start(m); } }}} (Note that with PJSUA-LIB, we can get the instance of the conference bridge by calling [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#g4b6ffc203b8799f08f072d0921777161 pjsua_set_no_snd_dev()]). With the above snippet, the irregularity of the sound device clock will be ''normalized'' by the master port, so the conference bridge will be run by the ''good'' clock. Of course this means some buffering is needed to compensate the ''clock'' difference between the sound device and the master port, and this is what the ''reverse channel'' of the ''splitcomb'' is for. The ''reverse channel'' can accommodate up to [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONFIG.htm#ga2e53b9eb4cb76294f95a15a2a0ef8cc PJMEDIA_SOUND_BUFFER_COUNT] frames, so if the clock difference is larger than this, you will need to enlarge {{{PJMEDIA_SOUND_BUFFER_COUNT}}} to an acceptable value (32, for example). === Does PJSIP support G.723 or G.729 codecs? === #g729-g723 Yes. The PJSIP distribution contains support Intel® Integrated Performance Primitive (IPP) library, which provides the G.723.1 and G.729 codecs. Please see [wiki:Intel_IPP_Codecs Using Intel® Integrated Performance Primitive (IPP) with PJMEDIA] on how to use this feature. In addition, PJSIP also supports using native codecs supported by Nokia handsets such as G.729, AMR-NB, and iLBC, via [wiki:Nokia_APS_VAS_Direct Nokia APS-Direct] method. If you can't or don't want to use Intel® IPP or APS-Direct, you can always create your own wrapper of course. Please see the next question on how to do this. === How can I add new codec to PJMEDIA? === #adding-codec First of all, read the [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CODEC.htm Codec Framework] documentation. Then, the easiest is to take other codec source file in {{{pjmedia-codec}}} directory, such as [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia-codec/gsm.c gsm.c], and replace GSM specific function calls with the functions that are provided by your codec library. There are two "classes" to implement: - The codec factory ([http://www.pjsip.org/pjmedia/docs/html/structpjmedia__codec__factory.htm pjmedia_codec_factory]) - Codec factory will be queried by PJMEDIA to see if it can instantiate a codec instance based on a codec descriptor ([http://www.pjsip.org/pjmedia/docs/html/structpjmedia__codec__info.htm pjmedia_codec_info]). Codec factory also provides information about what particular codecs it supports, so that PJMEDIA can list these codecs in the local SDP capability descriptor. - The codec itself ([http://www.pjsip.org/pjmedia/docs/html/structpjmedia__codec.htm pjmedia_codec]) - The codec instance provides functions to parse, encode and decode audio frames. Optionally it may provide a function to recover lost frames (known as ''Packet Lost Concealment'' feature, or PLC). Once it's finished, you should end up with just two public APIs exported by the implementation: an initialization function, and a deinitialization function. The initialization function's primary task is to register the codec factory to PJMEDIA's codec manager, so that PJMEDIA knows about this new codec. While the deinitialization function is to unregister the codec factory, and to release resources, if any. Then call the codec initialization function in the application. After this, the codec should be picked up automagically by the rest of PJMEDIA framework (that is, PJSIP should advertise the codec in outgoing SDP and negotiate it with remote's SDP, and encode/decode audio frames with the codec, if the codec is selected for the session). === How can I manipulate audio samples directly? === #audio-man In PJMEDIA, audio frames are sent back and forth between what is called [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__PORT__CONCEPT.htm media port (pjmedia_port)]. So to be able to peek or manipulate audio frames, we need to implement our own media port. Implementing media port should be easy. Basically we just need to implement these: 1. Create a media port structure, ''deriving'' from {{{pjmedia_port}}} structure: {{{ #!c struct my_media_port { pjmedia_port base; // Your data goes here: ... }; }}} 1. Fill in the media port information to describe the media port (like, the name, clock rate, bits per sample, etc.). Use [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__PORT__INTERFACE.htm#gb3259d2924c7a2243733391f6f8f0a9a pjmedia_port_info_init()] to initialize the port into. 1. Implement {{{get_frame()}}} callback (of the ''pjmedia_port'') if the media port is a source (that is, the media port feed audio frames to other media ports). 1. Implement {{{put_frame()}}} callback (of the ''pjmedia_port'') if the media port is a sink (that is, other media ports may feed audio frames to our media port). 1. Implement {{{on_destroy()}}}, if you need to reclaim resources when the media port is destroyed. There are many media port sample implementations in PJMEDIA. For source only media ports, samples include: - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjsip-apps/src/samples/playsine.c playsine.c] from the {{{pjsip-apps/samples}}} directory. - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/mem_player.c mem_player.c] from pjmedia (media port to playback audio from a buffer). - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/wav_player.c wav_player.c] from pjmedia (media port to playback audio from WAVE file). - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/tonegen.c tonegen.c] from pjmedia (media port to generate sine waves/DTMF/multi-frequency tones). For sink only media ports, samples include: - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/mem_capture.c mem_capture.c] from pjmedia (media port to save audio to a buffer). - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/wav_writer.c wav_writer.c] from pjmedia (media port to save audio to a WAVE file). For media ports that manipulates audio and provide both sink and source callbacks: - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/resample_port.c resample_port.c] from pjmedia (to convert sampling rate) - [http://www.pjsip.org/trac/browser/pjproject/trunk/pjmedia/src/pjmedia/echo_port.c echo_port.c] from pjmedia (the AEC) === I always get "Bad RTP pt" error. Why? === #bad-rtp-pt From our experience, this can be caused by one of these: 1. Remote endpoint has agreed to use one codec in the SDP negotiation, but it sends RTP with different codec. This had happened with some old version of a popular but not open source softphone (don't want to name it to protect the innocent). When this happens, the "Bad RTP pt" error message will be printed continuously in the log or screen (basically for every RTP packet!). The remedy in this case was to upgrade that softphone to a new version. 1. Remote endpoint is sending a comfort noise packet. When this happens, the error message is not printed as often as the other case (maybe once in every few seconds). When you encounter this problem, and if upgrading the softphone doesn't solve the problem, you can report this to PJSIP mailing list. When reporting, please include the error log and the complete INVITE message and the 200/OK response (containing the SDP), so that we can analyze which endpoint is behaving badly. ---- == Security Related Questions == #security === Does PJSIP Support TLS? === #tls Yes, PJSIP supports TLS since long time ago. For a little bit more information, please see [wiki:TLS Configuring and Using PJSIP with TLS] page. === How Can I Use TLS with PJSIP/pjsua === #pjsua-tls Please see [wiki:TLS Configuring and Using PJSIP with TLS] page. === Does PJSIP Support Secure Media? === #srtp PJSIP supports SRTP since version 0.9, please see [wiki:SRTP SRTP Support in PJSIP] page for more info. ---- == DTMF/Tone Related Questions == #dtmf === Why does PJSIP refuse to send DTMF to remote? === #rfc-2833 PJSIP will only send RFC 2833 DTMF to remote if remote has indicated its capability to accept RFC 2833 events in its SDP. This is done by putting this line in the SDP: {{{ a=rtpmap:101 telephone-event/8000 }}} Without receiving this capability indication, PJSIP will refuse to send RFC 2833 event, and a call to {{{pjsua_call_dial_dtmf()}}} or {{{pjmedia_session_dial_dtmf()}}} or {{{pjmedia_stream_dial_dtmf()}}} will return error code [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__ERRNO.htm#g043502be6c0961209feade822cdd79b7 PJMEDIA_RTP_EREMNORFC2833]. In this case, you can send the [#inband-dtmf DTMF tone inband] instead (see below). === How can I send inband DTMF tones? === #inband-dtmf It's quite easy with [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm PJSUA-LIB] API: 1. Once the call is established, create an instance of [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__MF__DTMF__TONE__GENERATOR.htm Tone Generator]. 1. Register this tone generator to pjsua's conference bridge, by calling [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#g833528c1019f4ab5c8fb216b4b5f788b pjsua_conf_add_port()]. 1. ''Connect'' the tone generator to the call, with [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#g3451304d677e013130dfb9e6b37e3ee6 pjsua_conf_connect()]. 1. Now instruct the tone generator to ''play'' some DTMF digits ([http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__MF__DTMF__TONE__GENERATOR.htm#gf7920b73983e1e09dfe883cbdd2861ae pjmedia_tonegen_play_digits()]). The digits then will be streamed to the call, and remote endpoint should receive the DTMF tone inband. Here is a snippet to do it: {{{ #!c struct my_call_data { pj_pool_t *pool; pjmedia_port *tonegen; pjsua_conf_port_id toneslot; }; struct my_call_data *call_init_tonegen(pjsua_call_id call_id) { pj_pool_t *pool; struct my_call_data *cd; pjsua_call_info ci; pool = pjsua_pool_create("mycall", 512, 512); cd = PJ_POOL_ZALLOC_T(pool, struct my_call_data); cd->pool = pool; pjmedia_tonegen_create(cd->pool, 8000, 1, 160, 16, 0, &cd->tonegen); pjsua_conf_add_port(cd->pool, cd->tonegen, &cd->toneslot); pjsua_call_get_info(call_id, &ci); pjsua_conf_connect(cd->toneslot, ci.conf_slot); pjsua_call_set_user_data(call_id, (void*) cd); return cd; } void call_play_digit(pjsua_call_id call_id, const char *digits) { pjmedia_tone_digit d[16]; unsigned i, count = strlen(digits); struct my_call_data *cd; cd = (struct my_call_data*) pjsua_call_get_user_data(call_id); if (!cd) cd = call_init_tonegen(call_id); if (count > PJ_ARRAY_SIZE(d)) count = PJ_ARRAY_SIZE(d); pj_bzero(d, sizeof(d)); for (i=0; itonegen, count, d, 0); } void call_deinit_tonegen(pjsua_call_id call_id) { struct my_call_data *cd; cd = (struct my_call_data*) pjsua_call_get_user_data(call_id); if (!cd) return; pjsua_conf_remove_port(cd->toneslot); pjmedia_port_destroy(cd->tonegen); pj_pool_release(cd->pool); pjsua_call_set_user_data(call_id, NULL); } }}} Since we're allocating resources for the call, these resources must be released once the call is disconnected. We should do this in {{{on_call_state()}}} callback: {{{ #!c static void on_call_state(pjsua_call_id call_id, pjsip_event *e) { pjsua_call_info call_info; pjsua_call_get_info(call_id, &call_info); if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) { call_deinit_tonegen(call_id); } } }}} With the above snippet, we just need to call '''call_play_digit()''' every time we need to send inband DTMF digit. === How Can I Detect Inband Tone === #tone-detect Currently PJMEDIA lacks built-in tone detection routine. But if you you have the routine, it shouldn't be straightforward to integrate it to the framework: 1. First, you need to wrap your routine as [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__PORT__CONCEPT.htm pjmedia_port] so that it can be plugged to the media framework. Your implementation would be similar to [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__FILE__REC.htm WAV writer] media port ([source:pjproject/trunk/pjmedia/src/pjmedia/wav_writer.c pjmedia/wav_writer.c]), but instead of writing to WAV file, it would monitor the audio signal for tone and call some callback when a tone is detected. 1. Once you have the tone detector media port implementation, you can just add this media port to the conference bridge with [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#g833528c1019f4ab5c8fb216b4b5f788b pjsua_conf_add_port()], and connect the audio source to your tone detector. === How Can I Send DTMF INFO Method? === #dtmf-info1 Please see the section on [#info-method sending INFO request with PJSUA-LIB]. ---- == Video Questions == === Does PJSIP support video? === #video Currently no. But one can handle video oneself in the application layer (please see below). === How can I add video support in PJSIP? === Since video stream is independent from audio stream, the simplest "integration" would be to not integrate video with pjmedia at all. In other words, the application would have to manage everything related to video (capture, render, codec, and RTP) by itself, separate from audio stream which is managed by pjmedia. Maybe you can use the media transports supplied by pjmedia, and the RTP module to pack/unpack RTP packets, to help you up a little bit, but apart from these, basically you'll have to do everything on your own. Also some processing needs to be done on the SDP to support video. So basically, for outgoing SDP, application has to add video information in the SDP after the SDP is created, and it has to parse video related information in the incoming SDP by itself. And perhaps if synchronization between audio and video is needed, the application then will need to peek the RTP packet coming to the audio stream. This can be done perhaps by modifying the media transport, or by installing media transport ''adapter'' as described in [#srtp-zrtp SRTP/ZRTP] question above. ---- == SIP Questions == #sip-questions === Does PJSIP support RFC XYZ? === #rfc The best way is to look at the [http://www.pjsip.org/sip_media_features.htm PJSIP Features] page and see if that particular feature is supported by PJSIP. === I'm having problem with calling XYZ, please help! === #general-sip Please report the problem to [http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org PJSIP mailing list]. Please provide the following information: 1. First thing first, '''always always''' mention the exact PJSIP version that you use, so that we can trace the problem to the particular version. 1. Please describe in detail what are you trying to accomplish and how do you configure your equipments (for example, do you use proxy? What kind of proxy? In NAT environments?). 1. It would be best to try to reproduce the problem with [http://www.pjsip.org/pjsua.htm pjsua], so that we can also try to reproduce your problem. 1. In any case, please provide the complete log file. If you use ''pjsua'', you can configure it to write log file with {{{--log-file}}} option. If you use your own application that is based on ''pjsua-lib'', you can write the log by setting {{{pjsua_logging_config.log_filename}}} field. === How can I use TCP transport to send/receive SIP messages? === #tcp Follow these steps to use SIP TCP transport: 1. First you must instantiate SIP TCP transport in your application. The TCP transport is enabled by default on pjsua so you can skip this test if you're using pjsua. 1. Then when sending outgoing requests, you need to tell PJSIP that the request is to be sent with TCP, by adding "{{{;transport=tcp}}}" parameter in the destination URI. This can be accomplished in two ways: - the most convenient way is to add a route-set entry (with proxy or outbound proxy setting) with TCP transport (e.g. with "{{{--proxy sip:myproxy;lr;transport=tcp}}}" arguments in pjsua). This way all requests will be sent with TCP via the proxy, and we don't need to change the URI for the registrar and all buddies in the buddy list. - if you don't want to configure route set entry, then you must add "{{{;transport=tcp}}}" parameter to all outgoing URIs (the registrar URI, the buddy URI, the target URI when making call, the target URI when sending MESSAGE, etc.). With PJSUA-LIB, when making or receiving calls with TCP, the local Contact header will automatically be adjusted to use the TCP transport. The client registration session also will keep the TCP connection active throughout the registration session, and server may send inbound requests using this TCP connection if it wants to. === I cannot login/REGISTER to my server. It complains about authentication error. === #authentication Most likely this is caused by wrong credential in the configuration. The remedy depends on what error was reported by PJSIP. For [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__CORE__ERRNO.htm#ga13bf24296c19bece7c0c9af051f89db PJSIP_ENOCREDENTIAL] error: - This error is caused by the realm specified in the credential doesn't match the realm challenged by the server in the 401/407 response. If you use PJSIP version 0.7-trunk or PJSIP version 0.7.1 or later, you can put wildcard ("*") as the realm to make PJSIP respond to any realms challenged by the server. If you use older PJSIP, you have to match the realm in the credential with the realm in the challenge. The realm normally would be equal to the domain name, but it doesn't have to. Asterisk, for example, always set the realm to "asterisk". For [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__CORE__ERRNO.htm#ga935d4205ae50ad6f18a4df98b90d2f6 PJSIP_EFAILEDCREDENTIAL] error: - If you encounter this error, most likely it was caused by a wrong credential. Check if the username and password combination is correct. === How can I attach user specific data to a call? === #call-user-data It depends on what user specific data means. If user data means an application data, normally a pointer to your application data structure, to be associated with a call, which you want to retrieve later, you can attach this application data with one of these: - For outgoing calls, specify the pointer in ''user_data'' argument when calling [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__CALL.htm#g502b0a6449cc5f67517b72df6a88c727 pjsua_call_make_call()]. - For incoming calls, call [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__CALL.htm#g53b9be88398324d940bf484df371d7d2 pjsua_call_set_user_data()] in {{{on_incoming_call()}}} callback to attach your user data. Once application data is attached to a call, you can retrieve it at any time by calling [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__CALL.htm#gfd0bf3368f982021cd9b9d3d1735ab6c pjsua_call_get_user_data()]. Now for a different view on the question. If by user data you mean to send custom SIP headers in outgoing SIP messages, you can put the custom headers in the [http://www.pjsip.org/pjsip/docs/html/structpjsua__msg__data.htm pjsua_msg_data] structure, which you can specify when sending SIP requests (for example, when sending INVITE, IM message, etc.). Here is a snippet on how to put a custom SIP header as ''pjsua_msg_data'': {{{ #!c .. pjsua_msg_data msg_data; pjsip_generic_string_hdr my_hdr; pj_str_t hname = pj_str("My-Header"); pj_str_t hvalue = pj_str("This is the content of My-Header"); pjsua_msg_data_init(&msg_data); pjsip_generic_string_hdr_init2(&my_hdr, &hname, &hvalue); pj_list_push_back(&msg_data.hdr_list, &my_hdr); // Specify the msg_data in pjsua_im_send(), for example pjsua_im_send(.., &msg_data, NULL); }}} The above snippet will add "{{{My-Header: This is the content of My-Header}}}" to outgoing IM request. More than one headers can be added to {{{pjsua_msg_data}}}, of course. === With ICE enabled, INVITE packet can exceed MTU/1500 bytes. How can I reduce the message size? === #sip-msg-size If MTU is an issue, the best solution is to use TCP or TLS transport rather than UDP transport where MTU will not be a problem. The following information is provided as a guideline to reduce message size. Please see ticket #342 for info. Basically there are few settings to configure to make PJSIP sends smaller packet: 1. Configure PJSIP to send compact form of SIP headers, by setting {{{PJSIP_ENCODE_SHORT_HNAME}}} macro to 1 in {{{config_site.h}}}. This will reduce SIP message size by approximately 50 bytes. 1. Suppress the inclusion of ''Allow'' header in outgoing requests, by setting {{{PJSIP_INCLUDE_ALLOW_HDR_IN_DLG}}} macro to 0 in {{{config_site.h}}}. This will reduce SIP message size by approximately 86 bytes. 1. Suppress the inclusion of SDP {{{rtpmap}}} attribute for static payload types, by setting {{{PJMEDIA_ADD_RTPMAP_FOR_STATIC_PT}}} macro to 0 in {{{config_site.h}}}. Note that this setting should not cause bad effects for communication, since SDP {{{rtpmap}}} attributes for static payload types are optional. This will reduce SIP message size by approximately 65 bytes. 1. Disable RTCP (advertisement) in SDP, by setting {{{PJMEDIA_ADVERTISE_RTCP}}} macro to 0 in {{{config_site.h}}}. When RTCP is disabled, no RTCP packets will be sent or received, and this will cause some RTCP TX statistics (including RTT report) to be unavailable. Other RTCP statistics such as RX statistics, as well as number of TX packets, will still be available since these values are generated locally. Disabling RTCP will reduce SIP message size by approximately 235 bytes for ICE with three candidates. 1. Last resort, disable some unused network interfaces in the system to reduce the number of ICE candidates advertised in SDP. On Windows for example, it's quite common to have some Loopback network interface, and disabling it doesn't seem to cause (too much) harm. 1. In pjsua, you can use {{{--use-compact-form}}} option to reduce the message size. Since PJSIP version 1.4, we have a feature to '''automatically switch transport to TCP''' when request size is larger than (default) 1300 bytes. See ticket #831 for more info. === How can I instantiate multiple PJSIP stacks in my application? === #multi-stack You don't need to. This may be necessary with other SIP stacks, but PJSIP inherently supports multiple identities (or accounts) throughout the libraries, so one instance of the stack can be used to perform multiple, separate registration and invite sessions. === How can I support INFO method or other SIP methods not mentioned in PJSIP? === #info-method Creating SIP method in pjsip is very simple: {{{ #!c const pjsip_method info_method = { PJSIP_OTHER_METHOD, { "INFO", 4 } }; }}} Once you have this, you can then create an [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__ENDPT__STATELESS.htm#g6a5dc2cd5b43a1adf869c9746593f818 independent request] or [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__DIALOG.htm#g8e057a2b3b89d071a2027eba4321751f request within dialog] of this method and send it [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__ENDPT__STATELESS.htm#g155a9b9dce2138e91605d6b7561d70a3 statelessly], [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__TRANSACT__UTIL.htm#ga4c9a6482b6077351daf2f7974ae7371 statefully], or [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__DIALOG.htm#gb2ec46bfa4a8fd5fdf96cda2bb477355 inside dialog]. The [http://www.pjsip.org/docs.htm Dev Guide PDF] will explain this in more detail. For DTMF INFO, [http://www.pjsip.org/pjsua.htm pjsua] application supports sending INFO request with ''application/dtmf-relay'' payload, please see [http://www.pjsip.org/pjsua.htm pjsua manual] for details. Also ''pjsua'' is able to handle incoming INFO request. Please see the source code of pjsua application for more information. === What is the difference between proxy and outbound proxy setting? === #proxy-outbound The {{{--proxy}}} option in [http://www.pjsip.org/pjsua.htm pjsua] application corresponds to {{{pjsua_acc_config.proxy}}} setting in PJSUA-LIB. This specifies the route set that is specific for the particular SIP account. The {{{--outbound}}} option corresponds to {{{pjsua_config.outbound_proxy}}} setting in PJSUA-LIB. This specifies a global route set that is applicable for the whole endpoint (rather than a particular account), and will be used for all accounts in the application. When {{{--service-route}}} option (this option corresponds to {{{pjsua_acc_config.enable_service_route}}} setting in PJSUA-LIB) is enabled for the account (default is disabled), the {{{--proxy}}} settings will be updated with the content of {{{Service-Route}}} header in successful REGISTER response. In other words, if {{{Service-Route}}} header is not present in 2xx REGISTER response, the {{{--proxy}}} settings for the account will be cleared. Unlike {{{--proxy}}} option, the route settings in {{{--outbound}}} option are not be affected by {{{Service-Route}}} processing. Both {{{--proxy}}} and {{{--outbound}}} options can be specified multiple times in ''pjsua'' command line to specify more than one servers. When both settings are present, the initial total route set for a particular account is built by appending the servers in {{{--proxy}}} option '''to''' the servers in {{{--outbound}}} option. For example: Account A has the following {{{--proxy}}} setting: {{{ --proxy sip:PA1;lr --proxy sip:PA2;lr }}} Account B has the following {{{--proxy}}} setting: {{{ --proxy sip:PB;lr }}} And the {{{--outbound}}} setting is the following: {{{ --outbound sip:PO;lr }}} With the above settings, the initial route set for account A will be computed as: {{{ Route: , , }}} While the initial route set for account B will be computed as: {{{ Route: , }}} If {{{--service-route}}} option is enabled for both accounts, and suppose the 2xx REGISTER responses for both accounts do not have {{{Service-Route}}} header, then the route sets for both accounts will be updated to contain only the outbound proxy: {{{ Route: }}} === How Can I Extract a Particular Header from Incoming Message === #pjsip_event The [wiki:SIP_Message_Buffer_Event] page describes in detail how to extract SIP messaging elements from a {{{pjsip_event}}} object. The {{{pjsip_event}}} object should have been provided in the callback. If you have {{{pjsip_rx_data}}} object rather than {{{pjsip_event}}} object, then extracting the SIP message is easier. You can find the SIP messaging elements (the SIP message and shortcuts to important headers) in {{{msg_info}}} field of the {{{pjsip_rx_data}}} object. === I'm having deadlock in my application. What went wrong? === #sip-deadlock You need to acquire mutexes in uniform order. Please see [wiki:PJSUA_Locks Mutex Lock Ordering in PJSUA-LIB] for more information. === How can I configure PJSIP for IMS? === #ims To configure PJSIP to register to an IMS/3GPP network, first declare these in your {{{config_site.h}}}: {{{ #!c #define PJSIP_HAS_DIGEST_AKA_AUTH 1 }}} Then configure pjsua with something like these: {{{ --id sip:alice@open-ims.test --registrar sip:open-ims.test --proxy sip:pcscf.open-ims.test:4060;lr --realm open-ims.test --username alice@open-ims.test --password alice --use-ims }}} === I'm trying to register to a server, but PJSIP treats the 200/OK response as unregistration. Why? === #regc '''''Update: this has been fixed by ticket #534. We're keeping this entry for reference only.''''' Since circa version 0.8 and up to version 0.9, the registration client session (pjsip_regc.c) has stricter checks on the Contact header(s) sent by registrar in the 200/OK response to REGISTER request. This is necessary to support multiple registrations (the same AOR is registered more than once in the server by multiple user agents), and this is how it is supposed to be done in the first place according to RFC 3261. Unfortunately this breaks "compatibility" with some servers, because these servers incorrectly return different Contact header(s) in the response, causing PJSIP to fail to find it's registered Contact header. When this happens, PJSIP will treat the response as unregistration response, regardless whether it's a successful (200 class) response. The treatment of Contact header(s) in REGISTER response are specified in ''Section 10.2.4 Refreshing Bindings'' of RFC 3261: ''"Each UA is responsible for refreshing the bindings that it has previously established. A UA SHOULD NOT refresh bindings set up by other UAs."'' ''"The 200 (OK) response from the registrar contains a list of Contact fields enumerating all current bindings. The UA compares each contact address to see if it created the contact address, using comparison rules in Section 19.1.4. If so, it updates the expiration time interval according to the expires parameter or, if absent, the Expires field value."'' Some common mistakes by the server: 1. Server modifies the Contact header when client is behind NAT. For example, client (PJSIP) sends this REGISTER request with private IP address in the Contact: {{{ REGISTER sip:pjsip.org SIP/2.0 Contact: .. }}} and server responds with this response which modifies the Contact header with the source (public) address of the request: {{{ SIP/2.0 200 OK Contact: ;expires=300 .. }}} This for example happens with wrong configuration in (Open)SER, where the configuration script uses '''fix_nated_contact()''' instead of '''fix_nated_register()''' in the registration handler. 1. Server does not return the '''exact''' URI in the response, causing URI comparison (to find the registered Contact header in the response) to fail. The URI comparison rules are very strict, and they are described in ''Section 19.1.4 URI Comparison'' of RFC 3261. Some of the points in the section: ''"An IP address that is the result of a DNS lookup of a host name does not match that host name."'' ''"A URI omitting any component with a default value will not match a URI explicitly containing that component with its default value."'' This means these two URI's are '''not equivalent''' (hostname vs IP address): {{{}}} [[BR]] {{{}}} And neither are these (port number is not specified, eventhough it's the default): {{{}}} [[BR]] {{{}}} Nor these (transport parameter is omitted, eventhough it's the default): {{{}}} [[BR]] {{{}}} ==== Solutions ==== There are few solutions to handle this situation: a. If the server is (Open)SER, use '''fix_nated_register()''' instead of '''fix_nated_contact()''' in the registration handler. a. For other servers, fix the server because it violates the standard. a. And finally as the last resort if you are unable to do the above, you can disable the strict registration Contact header checking in PJSIP. There are couple of new configuration options introduced in PJSIP v0.9 to control this: - to disable the strict checks on compile time, declare this in your {{{config_site.h}}}: {{{ #define PJSIP_REGISTER_CLIENT_CHECK_CONTACT 0 }}} - to disable the check on run-time, add this statement anywhere before sending the REGISTER request (you may do this even before initializing PJSIP) to change the process wide setting: {{{ #include pjsip_cfg()->regc.check_contact = PJ_FALSE; }}} When the strict check is disabled, the client registration session will calculate the expiration time (which determines whether it should treat the resposne as successful registration or unregistration) with the following rule instead: - it will skip the Contact headers and get the expiration time from the ''Expires'' header instead. - when ''Expires'' header is not present, it will get the value from the expires parameter of the Contact header, regardless of the URI specified in the Contact header === My machine has multiple NICs (multihomed) and PJSIP chooses the wrong IP interface === #multihomed If the machine is multihomed (such as when VPN is used), PJSIP will use the following logic to determine which IP address is used for the Contact and Via header. First of all, by default PJSIP binds sockets to INADDR_ANY (0.0.0.0), so it will be able to send and receive to/from any destinations configured in the system. An IP address will be choosen by using [http://www.pjsip.org/pjlib/docs/html/group__pj__addr__resolve.htm#g410b1bd02dcabf108b129e95368beef4 pj_gethostip()] function. Since version 1.2 this function selects which IP interface to use based on a scoring algorithm as follows: - add 1 to the score of the IP that is resolved from gethostbyname(gethostname()) - add 2 to the score of the IP that is used as the default interface - add 1 to the score of all interfaces from the interface enumeration. - add the end of the algorithm, choose interface with the highest score (Note: please see ticket #800 for the algorithm used on PJSIP version older than 1.2) This IP address then will be used in the Contact and Via header of the outgoing request If REGISTER is used, then this is becoming less of an issue. PJSUA-LIB will inspect the 200/OK response, check if the IP/port number seen by the server match the IP/port that we use in Contact, and if they're not the same, PJSUA-LIB will update the registration by sending un-REGISTER and new REGISTER with a new Contact. This new Contact then will be used for subsequent requests generated on behalf of the account. ---- == NAT Questions == #nat-questions === What NAT features does PJSIP support? === #nat-features Quite a few: - On the SIP side, PJSIP supports Symmetric Response Routing ({{{rport}}}) and STUN. - On the media side, application can choose the normal UDP media transport (with STUN support) or the ICE media transport. - The UDP media transport uses symmetric socket, and by default it will switch transmission to the source address of the RTP/RTCP packet if these addresses are different than the destination address. Application may disable this feature if it doesn't want it. - For the media, the [http://www.pjsip.org/pjmedia/docs/html/group__PJMED__STRM.htm media stream] will periodically transmit RTP packets during silence period, to keep NAT binding open. Also it will disable VAD for the first few hundred milliseconds after it is started, to ''hole-punch'' any NATs in between the endpoints. Please see [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONFIG.htm#g691ce80f0b4f2844cb9270af4665cdc8 PJMEDIA_CODEC_MAX_SILENCE_PERIOD] and [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONFIG.htm#gced8a0865fc8087f217067202b575f7f PJMEDIA_STREAM_VAD_SUSPEND_MSEC] settings on how to fine tune this behavior. - With ICE media transport, the transport periodically sends STUN keep-alive requests to keep NAT binding open, throughout the life of the application. The transport will also update its mapped address should the binding has changed. Note that this feature is not available for UDP media transport. === Which STUN-bis draft does PJNATH support? === #stunbis-std We support [http://tools.ietf.org/html/draft-ietf-behave-rfc3489bis-15 draft-ietf-behave-rfc3489bis-15]. But since STUN-bis (rfc3489bis) is updated often, please look at [http://www.pjsip.org/pjnath/docs/html/index.htm PJNATH documentation] for the most up to date information. === Which ICE draft does PJNATH support? === #ice-std We support [http://tools.ietf.org/html/draft-ietf-mmusic-ice-19 draft-ietf-mmusic-ice-19]. But since ICE is updated often, please look at [http://www.pjsip.org/pjnath/docs/html/index.htm PJNATH documentation] for the most up to date information. === Which TURN draft does PJNATH support? === #ice-std At the time of this writing, http://tools.ietf.org/html/draft-ietf-behave-turn-07 draft-ietf-behave-turn-07]. But since TURN is updated often, please look at [http://www.pjsip.org/pjnath/docs/html/index.htm PJNATH documentation] for the most up to date information. === What STUN-bis features does PJNATH support? === #stun-features Currently everything in RFC3489bis, including {{{MESSAGE-INTEGRITY}}} and {{{FINGERPRINT}}}. STUN over TCP is also supported, and it is used by the TURN client. === Is there any simple TURN client which I can use to test my TURN implementation? === #simple-turn-client Yes. There is a simple TURN client implementation in {{{pjnath/src/pjturn-client}}} directory, which will be built by default by the {{{make}}} command. If you use Visual Studio, you can build this application from within {{{pjnath/build/pjnath.dsw}}} workspace. This is a simple command line program to perform as STUN or TURN client. It supports STUN, TURN, short-term or long term credential, as well as FINGERPRINT mechanism. === Is there any simple TURN server in the samples? === #simple-turn-client Yes. There is a simple TURN '''server''' implementation in {{{pjnath/src/pjturn-srv}}} directory, which will be built by default by the {{{make}}} command. If you use Visual Studio, you can build this application from within {{{pjnath/build/pjnath.dsw}}} workspace. This is a simple command line program to perform as STUN or TURN server. It supports STUN, TURN, and long term credential, as well as FINGERPRINT mechanism. ---- == Performance == === How can I reduce the CPU usage/maximize the performance of my application? === #cpu There are few configuration settings to tweak to reduce the CPU usage of the application or to produce the best performance out of pjsip: 1. '''Echo canceller'''. The software AEC probably is the most CPU intensive module in PJSIP. To reduce the CPU usage, shorten the EC tail length to lower value (the {{{pjsua_media_config.ec_tail_len}}} setting), or even disable it altogether by setting {{{pjsua_media_config.ec_tail_len}}} to zero. 1. '''Codec'''. Use low complexity codec such as ''pcmu'' or ''pcma''. When using ''pcmu'' or ''pcma'', make sure pjmedia chooses the table based implementation, by setting {{{PJMEDIA_HAS_ALAW_ULAW_TABLE}}} macro to 1 (the default is normally enabled, but it may worth double-checking). 1. '''Avoid resampling'''. Resampling is a CPU intensive process, thus it should be avoided if you can, by choosing uniform clock rate for all media components (sound device, conference bridge, codecs, WAV files, etc.). 1. '''Choose effective sampling rate'''. Make sure that PJSUA-LIB selects the most effective sampling rate/clock rate for your application. For example, if the application only supports narrowband codecs (G.711, GSM, iLBC, G.723, or G.729), then the best sampling rate to choose would be 8KHz. Choosing higher sampling rate will only just waste CPU power since with higher sampling rate, the more processing is needed. With ''pjsua'', sampling rate can be forced with {{{--clock-rate}}} option. In the application, this can be achieved by setting {{{pjsua_media_config.clock_rate}}} field. 1. '''Logging'''. The default logging level is 5, which provides verbose information just in case some debugging is needed. When absolute performance is needed, you can decrease the logging verbosity level to 3 so that only vital information is displayed. This can be done by, either at compile time by setting {{{PJ_LOG_MAX_LEVEL}}} macro (in {{{config_site.h}}} as usual), or at run-time by calling {{{pj_log_set_level()}}}. 1. '''Threads'''. Use the optimum number of SIP worker threads in the application. The optimum number would be equal to the number of processors (or processor cores) in the system. 1. '''Run-time checks'''. All the libraries are equipped with run-time checks to prevent bad parameters from crashing the software. This feature can be disabled by setting {{{PJ_ENABLE_EXTRA_CHECK}}} to zero. 1. '''Stack checks'''. PJLIB is equipped with stack overflow detection. This feature can be disabled by setting {{{PJ_OS_HAS_CHECK_STACK}}} to zero. 1. '''Safe module'''. PJSIP is equipped with mutex protection to protect PJSIP modules from being unregistered while they are still being accessed by PJSIP. If the application doesn't add/remove modules dynamically during run-time, you can disable this protection by setting {{{PJSIP_SAFE_MODULE}}} to zero. 1. '''Unescape in place'''. By default, PJSIP will make a copy of escaped message sequence before unescaping it. You can configure PJSIP to unescape in place by setting {{{PJSIP_UNESCAPE_IN_PLACE}}} to one. Note that unescaping in place will modify the original message, so don't do this if the application needs to access the original message after it has been parsed (pjsip does not need this access). 1. '''Hash tolower optimization'''. By setting {{{PJ_HASH_USE_OWN_TOLOWER}}} to one, the hash function will convert the key to lower case and calculate the hash value in one loop. 1. '''Release mode'''. Don't forget to set the appropriate compiler optimization flag, and disable assertion with '''-DNDEBUG'''. === How can I configure pjsip to serve thousands of calls? === #high-perf There are few settings to tweak: 1. First apply the CPU reduction techniques above to maximize the performance. 1. Do not use PJSUA-LIB, for now. Please see the issues with using PJSUA-LIB to serve large number of calls [#pjsua-lib-perf below]. 1. By default, PJSIP is configured to handle only 16384 simultaneous SIP transactions and dialogs. This should be enlargeed according to the requirement, by setting both {{{PJSIP_MAX_TSX_COUNT}}} and {{{PJSIP_MAX_DIALOG_COUNT}}} to the appropriate values (for example, 640*1024-1). 1. If large number of TCP/TLS connections are needed, increase {{{PJ_IOQUEUE_MAX_HANDLES}}} to some large number (the default is only 64). 1. We've found that the simple GUID generator (used by GNU build system for *nix and MacOS X) will produce duplicate Id after approximately 2^14^ generations. This would cause things like transactions to have duplicated branch as previous transactions! On Linux, the {{{./configure}}} script will detect the presence of {{{libuuid}}} (part of [http://e2fsprogs.sourceforge.net/ e2fsprogs]) and use it if available, to avoid this problem. If you encounter this problem, please check if {{{libuuid}}} is available for {{{./configure}}} on your system. === I try to use PJSUA-LIB to develop a server like application, but performance is poor === #pjsua-lib-perf That is quite expected, unfortunately. PJSUA-LIB was initially aimed to build user agent client applications, so we didn't design it to handle large number of calls. The main reason why scalability is bad with PJSUA-LIB is because it uses single conference bridge to terminate all media (calls, WAV files, tone generators, etc.). A conference bridge runs strictly on one thread, which can be the sound device thread (the so called sound device ''clock'') or just a thread if no sound device is initialized. Because of this single thread restriction, it's quite easy to understand why PJSUA-LIB does not scale very well. We are currently looking for other design possibilities to make PJSUA-LIB scale better (suggestions are welcome!). In the meantime, perhaps you can use this approach to make the application scale better. Basically the idea is to manage the media in the application, rather than in PJSUA-LIB. Since we manage the media ourselves, we can design the media interconnection to whatever suit the requirements. One possible design is to create one conference bridge for each call, so that each call's media (including anything related to the call, such as WAV files, tone generators, outgoing call leg, etc.) runs on its own thread. Some steps to accomplish this are as follow: 1. First thing we should do is to stop the PJSUA-LIB's conference bridge from running. This can be accomplished by calling [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#g4b6ffc203b8799f08f072d0921777161 pjsua_set_no_snd_dev()]. With this call, PJSUA-LIB would not connect the conference bridge to any sound devices (including NULL sound device), so basically it would not run. 1. Because the main conference bridge is no longer running/working, we cannot use the usual PJSUA-LIB's API to add media ports (functions such as [http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm#g90a2ec9c8516b5ad13b061a46ae1d07a pjsua_player_create()]), since these API adds the media ports to the main bridge, which no longer works of course. 1. When a call's media is established (like when the call is CONFIRMED), PJSUA-LIB will still register the call's stream to the main bridge, but we can just ignore this. The main bridge has been stopped, so although the stream is ''registered'' to it, it won't try to retrieve or send any audio frames from/to the stream. 1. Since we're not using the main bridge anymore, the call's slot number in {{{pjsua_call_info.conf_slot}}} should not be used anymore. 1. Now that the main bridge has been stopped, we can manage the media ourselves. We can create one conference bridge for each call, and attach it to a master port to make it ''run'': {{{ #!c struct call_data { pj_pool_t *pool; pjmedia_conf *conf; pjmedia_port *cport; pjmedia_port *null; pjmedia_master_port *m; int call_slot; }; static void call_media_init(pjsua_call_id call_id) { pj_pool_t *pool; struct call_data *cd; pj_status_t status; pool = pjsua_pool_create("mycall", 1000, 1000); cd = PJ_POOL_ZALLOC_T(pool, struct call_data); cd->pool = pool; pjsua_call_set_user_data(call_id, (void*)cd); status = pjmedia_conf_create(pool, ..., PJMEDIA_CONF_NO_DEVICE, &cd->conf); cd->cport = pjmedia_conf_get_master_port(cd->conf); status = pjmedia_null_port_create(pool, ..., &cd->null); status = pjmedia_master_port_create(pool, cd->null, cd->cport, 0, &cd->m); status = pjmedia_master_port_start(cd->m); } }}} 1. Implement {{{on_stream_created()}}} callback of {{{pjsua_callback}}}. This callback notifies application when a stream has been created and about to be registered to the bridge. We'll use this callback to add the stream's media port to our own conference bridge: {{{ #!c static void on_stream_created(pjsua_call_id call_id, pjmedia_session *sess, unsigned stream_idx, pjmedia_port **p_port) { pjmedia_conf_add_port(cd->conf, cd->pool, *p_port, NULL, &cd->call_slot); } }}} 1. Add other media ports to the conference bridge as necessary. 1. Since stream may be destroyed during a call (for example, when call is put on hold), we need to remove the stream from our conference bridge when the stream is destroyed, otherwise application will crash because the conference bridge tries to retrieve/put audio frames from/to a non-existant stream. This can be done by implementing {{{on_stream_destroyed()}}} callback: {{{ #!c static void on_stream_destroyed(pjsua_call_id call_id, pjmedia_session *sess, unsigned stream_idx) { pjmedia_conf_remove_port(cd->conf, &cd->call_slot); } }}} 1. Finally, don't forget to release the resources when the call is disconnected. {{{ #!c static void call_media_deinit(pjsua_call_id call_id) { struct call_data *cd; cd = (struct call_data*) pjsua_call_get_user_data(call_id); if (!cd) return; pjmedia_master_port_stop(cd->m); pjmedia_master_port_destroy(cd->m, PJ_FALSE); pjmedia_conf_destroy(cd->conf); pjmedia_port_destroy(cd->null); ... pjsua_call_set_user_data(call_id, NULL); } static void on_call_state(pjsua_call_id call_id, pjsip_event *e) { pjsua_call_info call_info; pjsua_call_get_info(call_id, &call_info); if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) { call_media_deinit(call_id); } } }}} As mentioned earlier, we are currently looking for alternative design to arrange the media for better scalability, so if you have more ideas, they're most welcome! ---- == Footprint == === How can I reduce the footprint and heap usage of my application? === #footprint With the default settings, PJSIP is not really optimized for size (nor speed), since the main objective is to have sufficient information for troubleshooting. Taking Windows as reference platform, the executable size of Release build with Visual C++ 6 is as follows: {{{ pjsua_vc6.exe: file size=749,672 bytes 241664 .data 102400 .rdata 24576 .reloc 536576 .text (all numbers in decimal, bytes) }}} '''Note:''' with default settings, pjsua will include PJNATH/ICE implementation as well as many media goodies (e.g. all codecs), statically linked with the application, which you may not need in your embedded application. Hence the executable size is a bit large for ''pjsua''. The heap usage with 2 connected calls using Speex wideband codec and AEC enabled (press '''dd''' in pjsua menu, and scroll up to the portion where it dumps the memory pool statistic): {{{ >>> dd .. Total 908508 of 1046304 (86 %) used! .. }}} To reduce the executable size, you can apply the following settings: 1. '''Reduce logging verbosity'''. The default logging level is 5, which provides verbose information just in case some debugging is needed. You can decrease the logging verbosity level to 3 so that only vital information is displayed, by setting {{{PJ_LOG_MAX_LEVEL}}} macro (in {{{config_site.h}}} as usual). This will reduce executable size by approximately '''28 KB'''. 1. '''Turn off logging'''. Alternatively you can disable logging altogether, by setting {{{PJ_LOG_MAX_LEVEL}}} to 0. This will reduce executable size by another '''28 KB'''. 1. '''Disable Speex AEC''', by setting {{{PJMEDIA_HAS_SPEEX_AEC=0}}}, to reduce executable size by '''32 KB'''. 1. '''Disable resampling''', by setting {{{PJMEDIA_HAS_LIBRESAMPLE=0}}}, to reduce executable size by '''45 KB'''. 1. '''Disable unused codecs'''. To leave with only G.711 codecs (''pcma'' and ''pcmu''), disable speex with {{{PJMEDIA_HAS_SPEEX_CODEC=0}}}, disable iLBC with {{{PJMEDIA_HAS_ILBC_CODEC=0}}}, disable GSM codec with {{{PJMEDIA_HAS_GSM_CODEC=0}}}, and disable L16 codecs with {{{PJMEDIA_HAS_L16_CODEC=0}}}. This will reduce executable size by approximately '''114 KB'''. 1. '''Disable alaw/ulaw table'''. By default, a table based alaw/ulaw implementation is used. You can disable this by setting {{{PJMEDIA_HAS_ALAW_ULAW_TABLE=0}}}, which makes PJMEDIA to calculate the alaw/ulaw value rather than using the table. This will reduce executable size by approximately '''28 KB'''. 1. '''Disable error string'''. All libraries keep the description of the error codes in some static variables. You can omit this error description by setting {{{PJ_HAS_ERROR_STRING=0}}}. When the error description is omitted, {{{pj_strerror()}}} will just print the error code rather than the error description. You can then look for the error description in libraries source codes, or by searching on PJSIP website. Omitting the error description will reduce executable size by approximately '''20 KB'''. 1. '''Disable run-time checks'''. All the libraries are equipped with run-time checks to prevent bad parameters from crashing the software. You can disable this feature by setting {{{PJ_ENABLE_EXTRA_CHECK}}} to zero. This will reduce executable size by approximately '''20 KB'''. 1. '''Disable stack checks'''. PJLIB is equipped with stack overflow detection. You can disable this feature by setting {{{PJ_OS_HAS_CHECK_STACK}}} to zero, to reduce executable size by approximately '''4 KB'''. 1. '''Disable CRC32 table''', by setting {{{PJ_CRC32_HAS_TABLES=0}}}, to reduce executable size by about '''1 KB''', only if you use ICE. 1. '''Use your own sound device abstraction''', rather than !PortAudio. If you are porting PJSIP to an embedded platform, you will need to create your own sound device abstraction. So supposing we don't use !PortAudio and use the NULL sound device implementation ({{{PJMEDIA_SOUND_IMPLEMENTATION=PJMEDIA_SOUND_NULL_SOUND}}}), we will reduce executable size by approximately '''49 KB'''. With all above optimizations set, we now have pjsua size (still with ICE/PJNATH and many media goodies like conference, WAV, etc. '''statically linked''' in the executable): {{{ pjsua_vc6.exe: file size= 381,032 bytes 184320 .data 8192 .rdata 16384 .reloc 319488 .text }}} Using the same settings, if we take the executable size of '''simpleua.exe''' (this is a sample program to do simple call with audio, without conference bridge nor ICE/STUN): {{{ simpleua.exe: file size= 155,648 bytes 28672 .data 4096 .rdata 139264 .text }}} At this point, the heap memory usage of pjsua with 2 calls has been reduced by about 100 KB: {{{ >>> dd .. Total 793624 of 909024 (87 %) used! .. }}} We still want more heap usage reductions, of course! Now, assuming that the product will only need to support, say, 8 calls, we can apply these settings to '''reduce heap memory usage''': 1. '''Transaction/dialog/call count'''. Set the maximum number of concurrent transactions/dialogs/calls with {{{ #!c # define PJSIP_MAX_TSX_COUNT 31 # define PJSIP_MAX_DIALOG_COUNT 31 # define PJSUA_MAX_CALLS 31 }}} 1. '''Optimize pool sizes'''. These settings not only will reduce heap memory usage, but will also prevent the libraries from allocating too many large memory blocks. With the default settings, most memory pools are configured to allocate memory in 4KB blocks, and some system like Symbian will have difficulties in providing these blocks to PJSIP. Use the following setting to reduce the memory block size used by memory pools, at the expense of more calls to system's memory allocators ({{{new}}} or {{{malloc}}}) to allocate memory: {{{ #!c # define PJSIP_POOL_LEN_ENDPT 1000 # define PJSIP_POOL_INC_ENDPT 1000 # define PJSIP_POOL_RDATA_LEN 2000 # define PJSIP_POOL_RDATA_INC 2000 # define PJSIP_POOL_LEN_TDATA 2000 # define PJSIP_POOL_INC_TDATA 512 # define PJSIP_POOL_LEN_UA 2000 # define PJSIP_POOL_INC_UA 1000 # define PJSIP_POOL_TSX_LAYER_LEN 256 # define PJSIP_POOL_TSX_LAYER_INC 256 # define PJSIP_POOL_TSX_LEN 512 # define PJSIP_POOL_TSX_INC 128 # define PJMEDIA_SESSION_SIZE 1000 # define PJMEDIA_SESSION_INC 1000 }}} With these settings applied, heap memory usage will be reduced very significantly. Looking at heap memory usage of pjsua with two G.711 calls: {{{ pjsua_vc6 --clock-rate 8000 --ec-tail 0 --max-calls 2 --no-tcp >>> dd .. Total 120532 of 150344 (80 %) used! .. }}} So only about 150 KB for two calls, I think that should be affordable. ---- == Windows Specific Questions == === How can I use PJSIP in .NET applications? === #activex For this, you will need to have ActiveX wrapper for PJSIP. Unfortunately, at this point we don't provide ActiveX projects for PJSIP, but you can use one from this project: - [http://sipekphone2.googlepages.com/ Sipek Phone project], created by Sasa Coh, is a project to build a SIP softphone using .NET, and it has an PJSIP ActiveX wrapper as part of the project. === I'm not able to build PJSIP with Visual Studio 2008 === #vs2008 Q: I'm continuing to build under vs2008, I download the directxSDK and puts its lib and include dir into the pjsip project But I having a strange error during the build, the Microsoft compiler is complaing about que Microsoft code). Let me show the code and the error: {{{ Code: ULONG WINAPI GetIpStatisticsEx( OUT PMIB_IPSTATS Statistics, IN ULONG Family ); Error: 1>e:\arquivos de programas\microsoft sdks\windows\v6.1\include\iphlpapi.h(390) : error C2146: syntax error : missing ')' before identifier 'Statistics' }}} A: Quoting Alan J. Bond's [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-July/003667.html post on PJSIP mailing list]: Please check the version of Windows SDK you are using. Here are the details I previously posted about this problem: Windows SDK for Windows 2008 (6001.18000.367) has a typo in iphlpapi.h. The PJSIP project will not build with this SDK version unless iphlpapi.h is corrected. Nor will anything else using iphlpapi.h with _WIN32_WINNT defined as 0x4000 (for NT4 backward compatibility, not commonly used these days). It will throw up at this point in iphlpapi.h {{{ #if (NTDDI_VERSION >= NTDDI_XP) ULONG WINAPI GetIpStatisticsEx( OUT PMIB_IPSTATS Statistics, IN ULONG Family ); }}} ... complaining that PMIB_IPSTATS is undefined. This is because it erroneously enters this #if block because NTDDI_XP (which should be NTDDI_WINXP) is undefined. The NTDDI_xxx symbols are all defined in sdkddkver.h Please note that this is specific to this particular SDK version. Just find the above in iphlpapi.h and change NTDDI_XP to NTDDI_WINXP. ---- == MinGW Specific Questions == === How can I enable SIP TLS Transport on MinGW? === #mingw-tls There may be other ways to enable SIP TLS support in MinGW, but I found that these steps are probably the easiest: 1. Download [http://www.slproweb.com/products/Win32OpenSSL.html OpenSSL Win32 Installer]. Mine is version 0.9.8d. 1. Install to {{{C:\OpenSSL}}} (you may install to other directory, but this tutorial will refer to {{{C:\OpenSSL}}}) 1. Make copy or soft link to the OpenSSL MinGW libraries since '''{{{aconfigure}}}''' script expects to find {{{libssl.a}}} and {{{libcrypto.a}}}. With MinGW Bash shell: {{{ $ cd /c/OpenSSL/lib/MinGW $ ln -s libeay32.a libcrypto.a $ ln -s ssleay32.a libssl.a }}} 1. Run '''{{{aconfigure}}}''' script with specifying OpenSSL include and lib paths: {{{ $ cd /your/pjsip/directory $ ./aconfigure CFLAGS='-I/c/OpenSSL/include -O2' LDFLAGS='-L/c/OpenSSL/lib/MinGW' }}} 1. In the {{{aconfigure}}} output you may see some warnings about {{{openssl/ssl.h}}}, but I think that can be safely ignored as long as it concludes that OpenSSL installation is available. You should probably see something like these: {{{ ... checking for OpenSSL installations.. checking openssl/ssl.h usability... yes checking openssl/ssl.h presence... no aconfigure: WARNING: openssl/ssl.h: accepted by the compiler, rejected by the preprocessor! aconfigure: WARNING: openssl/ssl.h: proceeding with the compiler's result checking for openssl/ssl.h... yes checking for SSL_library_init in -lssl... yes checking for ERR_load_BIO_strings in -lcrypto... yes OpenSSL library found, SSL support enabled .. }}} 1. Enable TLS transport in your '''{{{pjlib/include/pj/config_site.h}}}''': {{{ #!c #define PJSIP_HAS_TLS_TRANSPORT 1 }}} 1. Now we can build the project: {{{ $ make dep $ make }}} ---- == Windows Mobile Specific Questions == === How can I build PJSIP for WinCE/Windows Mobile? === #wm-build Have a look at this [wiki:Getting-Started/Windows-Mobile Getting Started | Windows Mobile] page. === I've got link error when building pjsua_wince === This may happen with PJSIP version older than 0.9. Quoting [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-January/001509.html this mailing list post]: 1. Open \pjsip-apps\build\wince-evc4\wince_demos.vcw from Visual C++ (VS 2005) 1. Make a config_site.h 1. Change vsnprintf to vsprintf in \third_party\portaudio\src\common\pa_debugprint.c 1. Change target platform and SDK to one you want (e.g. Windows Mobile 5.0 PC emulator and Windows Mobile 5.0 SDK) and then compile Thanks Vishesh Sharma for the tips. === pjsua_wince doesn't seem to recognize project dependencies === The problem may be similar to [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-January/001541.html this thread in PJSIP list]: ''"The pjsua_wince workspace doesn't seem to recognize project dependencies. The libraries doesn't seem to be built when I build pjsua_wince, and I got tons of unresolved symbols during linking"''' If you follow the thread, in the end the reported just reinstalled the whole VS2005 and WM SDK, and things work as expected. === I keep getting PJ_ERESOLVE error on Windows Mobile === #wm-resolve From our experiments, this is caused by one of these: - When the networking is down, pjlib will return PJ_ERESOLVE error when trying to query the IP address of local hostname. - Bug in PJSIP, which caused PJ_ERESOLVE error even when the destination address is an IP address. This is supposed to be fixed in ticket #458. For more info on how to setup networking on Windows Mobile emulator, please see [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-February/001558.html Lakmal Molligoda post on PJSIP mailing list]. The solution in that post has been verified in [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-May/002892.html another discussion here]. === SIP request doesn't seem to reach the destination, and SIP transaction will time out === #wm-sip-timeout An example of this problem can be found on [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-February/001564.html this post on PJSIP mailing list]. From the post, it is reported that Internet Explorer (on the Emulator) is able to connect to network using a proxy, and from the log, PJSIP are sending SIP REGISTER requests to server, but this request cannot reach the server (nor the messages appear in Wireshark capture on local network) and the registration finally times out. This problem is caused by lack of network connectivity, just like [#wm-resolve PJ_ERESOLVE error on Windows Mobile] above. PJSIP (and SIP programs in general) does not work with HTTP proxy, so even if networking seems to be working with Internet Explorer with proxy configured, SIP messages won't be able to reach the destination unless networking is properly configured. Please see [#wm-resolve PJ_ERESOLVE error on Windows Mobile] topic above on how to configure networking on Windows Mobile/PocketPC emulator. === Bad audio quality on Windows Mobile === #wm-bad-audio [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-January/001534.html Tzury Bar Yochay posted this] on PJSIP mailing list: ''"Within a layout of Asterisk as server, a soft-phone on a desktop workstation (SJPhone), and pjsua_wince on WM5 device I am experiencing the following symptom: Voice spoken at the desktop end is heard well in the mobile device, but not the vice versa. e.g., words spoken on the mobile device yields a metallic effect in the PC Speaker."'' The solution is to increase the sound buffer count to accommodate audio frame burstiness on Windows mobile, by declaring this on your {{{config_site.h}}}: {{{ #!c #define PJMEDIA_SOUND_BUFFER_COUNT 16 }}} Increasing sound buffer count will increase audio latency, so please do some experiments to get the lowest value to get the best latency without breaking the audio quality. ---- == Linux/uC-Linux Specific Questions == === How can I build PJSIP for Linux/uC-Linux? === #linux-build Have a look at this [wiki:Getting-Started/Autoconf Getting Started | GNU] page. ---- == MacOS X Specific Questions == === How can I build PJSIP for MacOS X? === #osx-build Have a look at this [wiki:Getting-Started/Autoconf Getting Started | GNU] page. === How can I build universal binary for MacOS X? === #osx-universal Universal binary means one binary that will work for both Intel and PPC version of OSX. Ruud Klaver reported that the following configure command will build universal binary: {{{ $ CFLAGS="-arch ppc -arch i386 -O2" ./configure }}} === Are there any ready to use softphone or open source SIP client for MacOS X? === #osx-client Have a look at [http://www.remwave.com/Communicator/index.html Mac Communicator] from [http://www.remwave.com Remwave]. ---- == Symbian Specific Questions == #symbian === What Symbian Platforms and Development Tools are Supported by PJSIP? === As the supported platforms are constantly updated, please see [http://www.pjsip.org/sip_symbian.htm PJSIP for Symbian] page for the details. === How can I build PJSIP for Symbian? === #symbian-build We have provided a thorough instructions at the [http://www.pjsip.org/sip_symbian.htm PJSIP for Symbian] page, please check it out. In parallel, there is an even more thorough instructions on [wiki:DevelopingSymbianAppWithCarbide using PJSIP with Carbide C++ on S60 3rd Edition platform] which should cover everything including on-device debugging. === Missing Separator Error === #sym-missep One user [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-February/001608.html reported this compile error], something like: ''"\Symbian\9.1\S60_3rd_MR\EPOC32\BUILD\project\pjproject\build.symbian\PJLIB\GCCE\PJLIB.GCCE *** missing separator. Stop."'' This problem may be similar to [http://discussion.forum.nokia.com/forum/archive/index.php/t-74288.html this problem] reported on Nokia Forum. See if adding ARM toolchain to the PATH ({{{C:\Program Files\CSL Arm Toolchain\bin}}}) solves it. If not, please check that you have the correct Perl version for the SDK. Try reinstalling everything (Perl, ARM toolchain, and SDK) and see if it helps. '''Update:''' Samer Faour reported [http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-May/002830.html a working fix for this problem] in PJSIP list. Please follow his instructions in the link for a possible fix. === Fail to Install TRK Application on the Phone === #sym-trk ''I followed the Symbian tutorial and got this error when installing TRK application on my N70 phone:'' ''"The application installer in the phone does not support the file format of the application that was tried to be installed."'' The Nokia N70 phone is a S60 2nd Edition device thus it will not work with the tutorial since the tutorial uses S60 3rd Edition. If you wish to work on S60 2nd Edition device, you will need to download the appropriate SDK first. But please note that we have not tested PJSIP with S60 2nd Edition, so few things may not work. For example, you may not get full duplex audio, and also some instructions on the tutorial may not apply anymore. Your mileage may vary. === How to play audio to the earpiece rather than to the loudspeaker? === #sym-audio-routing With '''Multimedia Streaming''' API that we use as the implementation of sound device on Symbian, audio will be played to the loudspeaker by default, and this API does not provide the capability to switch the audio to earpiece (or in Nokia term, private audio device). So the short answer to the question is, no, we can't. But there could be some workarounds: - if you plug-in headset or accessory device to your phone, the audio will be routed to the headset automatically. - some say that if you reduce the audio level played to the speaker, the phone will automatically switch the audio routing to earpiece. I haven't verified this myself though. Alternatively you can use the '''Audio Proxy Server (APS)''' or '''VoIP Audio Services (VAS)''' backend for the sound device (please see next entry below), and with these API's it is possible to control the audio routing on the phone. And with these backends, by default the audio routing will be set to the earpiece. Application may change the routing by calling {{{pjmedia_snd_aps_activate_loudspeaker()}}} But please also note that there are some known problems with some Nokia S60 3rd Edition devices with regard to switching to use the earpiece with APS, please see this [http://wiki.forum.nokia.com/index.php/Wiki_Home: KIS000612 issue on Nokia forum] for more info. === How can I enable Audio Proxy Server (APS) in my application? === #sym-aps Please follow the guideline in [wiki:APS this page]. === I get "Panic KERN-EXEC 3" in Audio Server when running the application on emulator === #symaudkexec3 We get this message on S60 3rd Edition FP1 emulator (on Carbide's console output): {{{ Thread MMFAudioServer.exe::Local-01e5e324 Panic KERN-EXEC 3 }}} This happens on subsequent (SIP) calls on the emulator. Restarting the emulator should fix it. === I get one way audio when running the application on emulator === #sym1wayaud This is expected problem with the emulator (on all S60 3rd Edition versions up to FP1 at least). The Symbian streaming device backend on the emulator doesn't seem to be able to do full-duplex audio, and in our case, the recording direction always fails. PJSIP will report some error when opening the audio device, but otherwise the call should proceed okay (with one way audio). === I get ICE negotiation failure when running the sample console application === #symicefail We encountered this when running the sample console application with log verbosity greater than three. We suspect this is caused by the logging messages taking much of the CPU processing time, causing the ICE connectivity checks to time out. This was fixed by setting the console log verbosity to three. Note that too many console logging messages will also disrupt the audio. === I get device reboots, no audio, or distorted audio with APS === #symapsprob Symptoms: - device reboots itself when the application is trying to use the sound device (such as before call), - loss of audio, even though the log says that audio devices have been opened successfully, or - distorted audio All of these problems may be caused by these: - Wrong APSServer version installed on your phone. - in one of our experiments, we built the application with APSServer 2.40(3) SDK while the version installed on FP1 phone is 2.31(0), and this caused the no audio problem. - This is related to [http://wiki.forum.nokia.com/index.php/KIS000796_-_Frame_length_variation_for_G.711_encoder G.711 frame size variation issue] while our APS implementation '''was''' hardcoded to use 20ms G.711 frame size: - we suspect that running the application on devices which has 10ms frame size may crash the phone, or - if you're building the application with 10ms frame size and run it on device which has 20ms frame size, you will get distorted audio. Solutions: - the frame size issue has been fixed by ticket #680/#690 which will be available on PJSIP release [milestone:release-1.1 1.1] and [milestone:release-1.0.2 1.0.2]. - please use the latest APS version (currently 2.40(3)), and make sure the APSServer version installed on your device matches the APS SDK/plug-in when building the application. === Various Carbide Load Failed/TRKProtocolPlugin error === #trk Errors such as: - file I/O fault. makesis.exe returned with exit value == 1. The process cannot access the file because it is being used by another process. - TRKProtocolPlugin: Failed to download the specified file to target. - TRKProtocolPlugin: Failed to continue thread. - Target request failed: TRKProtocolPlugin: Can't connect to TRK (TRK may not be running on the phone or mismatch between selected and connected com port.). - Load Failed: TRKProtocolPlugin: Failed to launch the application (Installing the application may have failed or dependent libraries may be missing) - Load Failed: TRKProtocolPlugin: Unable to install the application. If self signing, certificate could be invalid if your PC clock is ahead of your phone clock. If not, your developer certificate may be invalid or UID of your application may be invalid or already in use. Please see [wiki:Getting-Started/Symbian#CommonProblems Common Problems] section in the [wiki:Getting-Started/Symbian Symbian Getting Started] wiki. ---- == Miscellaneous == === How can I use PJSIP in Python? === #python Start with this small [wiki:Python_SIP_Tutorial PJSIP Python Tutorial] page. It's not a comprehensive tutorial by any means, but hope that can give you a start. === How can I use PJSIP in TCL? === #tcl Antonio F. Cano Damas and Mats Bengtsson have contributed TCL binding for PJSIP, please have a look in the [http://www.pjsip.org/contrib.htm PJSIP Contribution] page.