33 | | == SIP and Media Interaction == |
34 | | |
35 | | Before we discuss how to integrate third party media library with PJSIP, we need to understand how PJSIP interacts with the media stack (PJMEDIA, in this case). This interaction/integration is done by either PJSUA-LIB or application, depending on whether the application uses PJSUA-LIB or PJSIP directly. |
36 | | |
37 | | There are few places where PJSIP and PJMEDIA interact with each other: |
38 | | * '''During call/invite session creation''': we need to specify local SDP when creating invite session. |
39 | | * '''After SDP negotiation''': once SDP has been negotiated, we can start our media streaming. |
| 33 | == SIP and Media Integration == |
| 34 | |
| 35 | Depending on which API abstraction layer being used by application (PJSUA-LIB or PJSIP/PJMEDIA API directly), integration between PJSIP and PJMEDIA happens in either PJSUA-LIB library or in application code. In this integration, there are few places where PJSIP and PJMEDIA interact with each other: |
| 36 | * During call/invite session creation -- we need to specify local SDP when creating invite session. |
| 37 | * After SDP negotiation -- once SDP has been negotiated, we can start our media streaming. |
46 | | An invite session is created by application (or PJSUA-LIB) when we make outgoing call or when we receive incoming call. We need to specify our local SDP when creating the invite session, because SDP negotiation will be done by the invite session [*], and to do this it needs SDP from both local and remote endpoints. Normally application just need to ask PJMEDIA to create local SDP for us, based on capabilities that have been registered to it. |
47 | | |
48 | | ''[*] To be precise, the negotiation actually is done by the SDP negotiator (part of PJMEDIA/PJSDP library) which will be invoked by the invite session. The decision to make SDP negotiation as integral part of invite session is to shield application from the complexity of SDP offer/answer session (for example, with late offer/answer, offer/answer quirks related to the use of PRACK, and ability to update session early with UPDATE), while maintaining the flexibility for the application to control when and what offer and answer to be given to remote.'' |
49 | | |
50 | | Below is the pseudo-code for creating a call/invite session. The procedure is relatively similar for both caller and callee. |
| 44 | An [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__INV.htm invite session] is created by application (or PJSUA-LIB) when we make outgoing call or when we receive incoming call. We need to specify our local SDP when creating the invite session, because SDP negotiation will be done by the invite session [*], and to do this it needs SDP from both local and remote endpoints. |
| 45 | |
| 46 | ''[*] To be precise, the negotiation actually is done by the [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__SDP__NEG.htm SDP negotiator] (part of PJMEDIA/PJSDP library) which will be invoked by the invite session. The motivation to make SDP negotiation as integral part of invite session is to shield application from the complexity of SDP offer/answer session (for example, with late offer/answer, offer/answer quirks related to the use of PRACK, and ability to update session early with UPDATE), while maintaining the flexibility for the application to control when and what offer and answer to be given to remote.'' |
| 47 | |
| 48 | Below is the pseudo-code for creating a call/invite session. The procedure is relatively similar for both caller and callee. For a working sample, please see [http://www.pjsip.org/pjsip/docs/html/page_pjsip_sample_simple_ua_c.htm '''simpleua''' sample] or PJSUA-LIB source code. |
101 | | As discussed above, SDP negotiation is done by the SDP negotiator object that is invoked internally by the invite session. The invite session user (application or PJSUA-LIB) will get notification whenever the SDP negotiation has been done, via invite session's '''on_media_update()''' callback. |
102 | | |
103 | | The ''on_media_update()'' callback contains ''status'' parameter which tells application whether SDP negotiation has been successful (or not). We are normally only interested with the successful status to start our media. |
104 | | |
105 | | Below is the pseudo-code to implement ''on_media_update()'' callback. You can see a working implementation of this function in ''pjsua_call_on_media_update()'' function of {{{pjsua_call.c}}} in PJSUA-LIB. |
| 115 | As discussed above, SDP negotiation is done by the [http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__SDP__NEG.htm SDP negotiator] object that is invoked internally by [http://www.pjsip.org/pjsip/docs/html/group__PJSIP__INV.htm the invite session]. The invite session user (application or PJSUA-LIB) will get notification whenever the SDP negotiation has been done, via invite session's '''on_media_update()''' callback. |
| 116 | |
| 117 | The [http://www.pjsip.org/pjsip/docs/html/structpjsip__inv__callback.htm#aafbe25fa41f5aa57dfe5a42bf025f2d on_media_update()] callback contains ''status'' parameter which tells application whether SDP negotiation has been successful (or not). We are normally only interested with the successful status to start our media. |
| 118 | |
| 119 | Below is the pseudo-code to implement ''on_media_update()'' callback. You can see a working implementation of this function in [http://www.pjsip.org/pjsip/docs/html/page_pjsip_sample_simple_ua_c.htm simpleua sample] or ''pjsua_call_on_media_update()'' function of {{{pjsua_call.c}}} in PJSUA-LIB. |
176 | | For both of these two callbacks, application MUST provide a local SDP to the invite session. The process of getting local SDP is similar to the one when creating a call/invite session above. |
177 | | |
178 | | For a working sample, please see ''pjsua_call_on_rx_offer()'' and ''pjsua_call_on_create_offer()'' functions in {{{pjsua_call.c}}} file of PJSUA-LIB. |
| 198 | Application MUST provide a local SDP to the invite session in both callbacks. The process of getting local SDP is similar to the one when creating a call/invite session above. For a working sample, please see ''pjsua_call_on_rx_offer()'' and ''pjsua_call_on_create_offer()'' functions in {{{pjsua_call.c}}} file of PJSUA-LIB. |
| 199 | |
| 200 | For further reference, please see: |
| 201 | * [http://www.pjsip.org/pjsip/docs/html/structpjsip__inv__callback.htm Invite Session callback] |
| 202 | |
184 | | We have two approaches on how to integrate your third party media stack with PJSIP: |
185 | | 1. to completely remove PJMEDIA from application dependency |
186 | | 1. reuse PJMEDIA's session info |
| 208 | We have three approaches on how to integrate your third party media stack with PJSIP: |
| 209 | 1. to only use SDP components of PJMEDIA and nothing else (the SDP messaging, parsing, and offer answer negotiation are still needed since they are tightly coupled with the invite session for the reasons explained above). |
| 210 | 1. above, plus to reuse PJMEDIA's session info generation to avoid working with SDP directly. |
207 | | 1. Create a new library which consists of the following files from PJMEDIA directory (note that on GNU and Symbian build systems, a library containing these files has been provided and it's called {{{pjsdp}}} library): |
208 | | - errno.c |
209 | | - sdp.c |
210 | | - sdp_cmp.c |
211 | | - sdp_neg.c |
212 | | 1. To create a local SDP for the invite session (either when creating the call or when the invite session needs updated offer or answer), you need to build the SDP manually. You cannot use {{{pjmedia_endpt_create_sdp()}}} function since this function is part of PJMEDIA. |
| 229 | 1. Link with the appropriate library: |
| 230 | - On Symbian or GNU build system, link the application with PJSDP library and exclude PJMEDIA from the link process. |
| 231 | - On other build system, you may link with PJMEDIA to get the SDP components linked with application, but do not use anything else. |
| 232 | - Alternatively you may create a new library which consists of the following files from PJMEDIA directory: errno.c, sdp.c, sdp_cmp.c, and sdp_neg.c |
| 233 | 1. You need to build the SDP manually for the invite session (either when creating the call or when the invite session needs updated offer or answer). You cannot use {{{pjmedia_endpt_create_sdp()}}} function since this function is part of PJMEDIA. |
230 | | 1. application needs to link with PJMEDIA library to get the SDP parts and the SDP generation/conversion to media session info functionality. |
231 | | 1. implement a codec factory for each codec that the third party media stack supports. The codec factory is needed to register the codec into codec manager's codec list. Note that only the codec factory needs to be implemented (the ''pjmedia_codec_factory_op'' API); no need to implement the codec operation itself (the ''pjmedia_codec_op'' API), since we will never create PJMEDIA's stream so no ever codec will get instantiated. |
232 | | 1. The operations that need to be implemented in ''pjmedia_codec_factory_op'' are: |
| 251 | 1. Application needs to link with PJMEDIA library to get the SDP, the SDP generation/conversion and codec information parts of PJMEDIA. |
| 252 | 1. Implement a codec factory for each codec that the third party media stack supports, to register the codec information into PJMEDIA. Note that only the codec factory needs to be implemented, since we will never create PJMEDIA's stream so no codec will ever gets instantiated. |
| 253 | 1. The operations in ''pjmedia_codec_factory_op'' that need to be implemented are: |
236 | | 1. create a ''pjmedia_endpt'' instance, and registers each of the codec factories into the codec manager (application can query the codec manager instance from the ''pjmedia_endpt''). |
237 | | 1. the code to create a call or to handle media update event is similar to the generic pseudo-code explained earlier, except that application will replace call to ''pjmedia_session_create()'' with the corresponding function provided by the third party media stack to start the media. |
| 257 | 1. You can use the sample codec implementations as a template to create your codec factories. ''Hints: you may use one codec factory to register multiple types of codecs''. |
| 258 | 1. Create a ''pjmedia_endpt'' instance, and registers each of the codec factories into the codec manager (application can query the codec manager instance with [http://www.pjsip.org/pjmedia/docs/html/group__PJMED__ENDPT.htm#ge058aeedcfad28aa6293308c65429760 pjmedia_endpt_get_codec_mgr()] function). |
| 259 | 1. The code to create a call or to handle media update event is similar to the generic pseudo-code explained earlier, except that application will replace call to [http://www.pjsip.org/pjmedia/docs/html/group__PJMED__SES.htm#g6bb6bcc4721ca9f357b5e3bb750378c6 pjmedia_session_create()] with the corresponding function provided by the third party media stack to start the media. |
245 | | 1. We probably no longer use PJMEDIA to control the media flow, and if this is the case, we'll need to stop the media from running. Follow [wiki:FAQ#pjsua-lib-perf this article on PJSIP FAQ] on how to manage our own media with PJSUA-LIB. |
246 | | 1. Re-implement ''pjmedia_session_create()'' function in PJMEDIA's {{{session.c}}} with your implementation (that uses the third party media stack). Also re-implement: |
247 | | - pjmedia_session_destroy(): to destroy the media session |
248 | | - pjmedia_session_get_port(): just return a dummy media port. This wouldn't matter since media flow is not running in PJSUA-LIB so the media port will never be used. |
249 | | - pjmedia_session_dial_dtmf(), pjmedia_session_check_dtmf(), pjmedia_session_get_dtmf(), and pjmedia_session_set_dtmf_callback() |
250 | | 1. You'd also probably need to re-implement the UDP media transport. The media transport is needed to get its socket address info (to be advertised in SDP), but it needs to be re-implemented to '''not''' actually bind to the specified socket address (otherwise if your media stack tries to bind to the same address, it will fail). |
| 267 | 1. Since we no longer use PJMEDIA to control the media, we need to stop the media in PJSUA-LIB from running. Follow [wiki:FAQ#pjsua-lib-perf this article on PJSIP FAQ] on how to manage our own media with PJSUA-LIB. |
| 268 | 1. Re-implement ''pjmedia_session_create()'' function in PJMEDIA's {{{session.c}}} with your implementation (that uses the third party media stack). You may just return a dummy session here if you decide to handle media session creation in the application code (in ''on_stream_created()'' callback of PJSUA-LIB. Please see the FAQ article above for the details). |
| 269 | 1. You'd also probably need to re-implement the UDP media transport. The media transport is needed because PJSUA-LIB will instantiate them to get their socket addresses (to be advertised in SDP). You still need to implement the UDP media transport even when your media stack handles the transport (because PJSUA-LIB still needs to retrieve the socket addresses); in this case, it needs to be re-implemented so that it's '''not''' actually binding to the specified socket address, or otherwise if your media stack tries to bind to the same address, it will fail. |