2006-12-21 06:30:28 +00:00
|
|
|
|
/* -*- text -*- */
|
|
|
|
|
|
|
|
|
|
/**@MODULEPAGE "nua" - High-Level User Agent Module
|
|
|
|
|
|
|
|
|
|
@section nua_meta Module Meta Information
|
|
|
|
|
|
|
|
|
|
The @b nua module contains the user-agent library taking care of basic
|
|
|
|
|
SIP User Agent functions. Its functionality includes call management,
|
|
|
|
|
messaging and event retrieval.
|
|
|
|
|
|
|
|
|
|
@CONTACT Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
|
|
|
|
|
|
|
|
@STATUS @SofiaSIP Core library
|
|
|
|
|
|
|
|
|
|
@LICENSE LGPL
|
|
|
|
|
|
|
|
|
|
@par Contributor(s):
|
|
|
|
|
- Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
|
|
|
- Pasi Rinne-Rahkola <Pasi.Rinne-Rahkola@nokia.com>
|
|
|
|
|
- Kai Vehmanen <Kai.Vehmanen@nokia.com>
|
|
|
|
|
- Martti Mela <Martti.Mela@nokia.com>
|
|
|
|
|
|
|
|
|
|
@section nua_overview Overview
|
|
|
|
|
|
|
|
|
|
The NUA API gives the high-level application programmer transparent and
|
|
|
|
|
full control to the SIP protocol engine<6E>below it. NUA provides the call
|
|
|
|
|
semantics on top of existing transaction semantics found in
|
|
|
|
|
<a href="../nta/index.html"><b>nta</b></a> module.
|
2007-08-06 19:24:10 +00:00
|
|
|
|
With NUA it is possible to create different kind of SIP User Agents,
|
2006-12-21 06:30:28 +00:00
|
|
|
|
like terminals, gateways or MCUs.
|
|
|
|
|
|
|
|
|
|
The @b nua engine hides many low-level signaling and media management
|
|
|
|
|
aspects from the application programmer. It is possible to use different
|
|
|
|
|
kind of media interfaces - even remote ones - in a fully transparent way.
|
|
|
|
|
|
2007-08-06 19:24:10 +00:00
|
|
|
|
The application and the protocol engine within User Agent library can be run
|
|
|
|
|
in separate threads. The protocol engine communicates with the application
|
|
|
|
|
using @ref nua_event_e "events", delivered to the application with a a
|
|
|
|
|
callback function. The callback function is called within the thread context
|
|
|
|
|
of the application, represented with a #su_root_t object.
|
2006-12-21 06:30:28 +00:00
|
|
|
|
|
|
|
|
|
@section nua_concepts_user Sofia Concepts for NUA User
|
|
|
|
|
|
|
|
|
|
@subsection nua_intro Introduction
|
|
|
|
|
|
|
|
|
|
The Sofia software suite is based on certain basic ideas and concepts that
|
|
|
|
|
are used in all levels of Sofia software. Many of those are implemented in
|
|
|
|
|
Sofia utility library (<a href="../su/index.html"><b>su</b></a>) providing
|
|
|
|
|
unified interface to the most important OS services and utilities .
|
|
|
|
|
|
|
|
|
|
The following sections contain descriptions of the concepts that a user of
|
|
|
|
|
NUA library must understand to create a working application. The other
|
|
|
|
|
utilities (in the SU library and other libraries of Sofia software suite)
|
|
|
|
|
might also be useful for an application developer but one must be careful
|
|
|
|
|
when using them because they might change the behavior of the Sofia
|
|
|
|
|
software suite in a way that causes NUA library to work incorrectly.
|
|
|
|
|
See [<a href="../su/index.html"><b>su</b></a>] for more detailed
|
|
|
|
|
description of the SU services.
|
|
|
|
|
|
|
|
|
|
@subsection nua_root Event loop - root object
|
|
|
|
|
|
|
|
|
|
The NUA uses the reactor pattern (also known as dispatcher pattern and
|
|
|
|
|
notifier pattern) for event driven systems (see [Using Design Patterns
|
|
|
|
|
to Develop Reusable Object-oriented Communication Software, D.C. Schmidt,
|
|
|
|
|
CACM October '95, 38(10): 65-74]). Sofia uses a task as basic execution
|
|
|
|
|
unit for the programming model. According to the model, the program can
|
|
|
|
|
ask that the event loop invokes a callback function when a certain event
|
|
|
|
|
occurs. Such events include I/O activity, timers or a asynchronously
|
|
|
|
|
delivered messages from other task.
|
|
|
|
|
|
|
|
|
|
The root object is a handle representing the task in the application.
|
|
|
|
|
Another way of seeing the same thing is that the root object represents
|
|
|
|
|
the main event loop of the task. Through the root object the task code
|
|
|
|
|
can access its context information (magic) and thread-synchronization
|
|
|
|
|
features like wait objects, timers, and messages.
|
|
|
|
|
|
2007-08-06 19:24:10 +00:00
|
|
|
|
An application using NUA services must create a root object and the callback
|
|
|
|
|
routine to handle @ref nua_event_e "NUA events". The root object is created
|
|
|
|
|
with su_root_create() function and the callback routine is registered with
|
2006-12-21 06:30:28 +00:00
|
|
|
|
nua_create() function.
|
|
|
|
|
|
|
|
|
|
Root object has type #su_root_t.
|
|
|
|
|
|
2007-08-06 19:24:10 +00:00
|
|
|
|
See documentation of <sofia-sip/su_wait.h> and <su_root.c> for more information
|
2006-12-21 06:30:28 +00:00
|
|
|
|
of root object.
|
|
|
|
|
|
|
|
|
|
See section #nua_event_e for more information of the callback function.
|
|
|
|
|
|
|
|
|
|
@subsection nua_magic Magic
|
|
|
|
|
|
|
|
|
|
The magic is a term used for the context pointer that can be bound
|
|
|
|
|
to various objects in Sofia stack (for example root object and operation
|
|
|
|
|
handle) by the application code. This context pointer is passed back
|
|
|
|
|
to the application code when a registered callback function is called by
|
|
|
|
|
the main event loop. The Sofia stack retains the context information between
|
|
|
|
|
calls to the callback function. An application can use the context information
|
|
|
|
|
to store any information it needs for processing the events.
|
|
|
|
|
|
|
|
|
|
@subsection nua_memmgmt Memory Handling
|
|
|
|
|
|
|
|
|
|
The home-based memory management is useful when a lot of memory blocks are
|
|
|
|
|
allocated for given task. The allocations are done via the memory home,
|
|
|
|
|
which keeps a reference to each allocated memory block. When the memory
|
|
|
|
|
home is then freed, it will free all memory blocks to which it has
|
|
|
|
|
reference. This simplifies application logic because application code does
|
|
|
|
|
not need to keep track of the allocated memory and free every allocated block
|
|
|
|
|
separately.
|
|
|
|
|
|
|
|
|
|
An application using NUA services can use the memory management services
|
|
|
|
|
provided by the SU library but it is not mandatory.
|
|
|
|
|
|
2007-08-06 19:24:10 +00:00
|
|
|
|
See documentation of <sofia-sip/su_alloc.h> for more information of memory
|
|
|
|
|
management services.
|
2006-12-21 06:30:28 +00:00
|
|
|
|
|
|
|
|
|
@subsection nua_tags Tags
|
|
|
|
|
|
|
|
|
|
Tagging is the mechanism used in Sofia software for packing parameters to
|
|
|
|
|
functions. It enables passing a variable number of parameters having
|
|
|
|
|
non-fixed types. For an application programmer the tagging is visible as
|
|
|
|
|
macros that are used to encapsulate the passed parameters. When evaluated a
|
|
|
|
|
tagging macro creates a structure that contains a tag (telling what is the
|
|
|
|
|
type of a parameter) and a value (pointer to opaque data). By checking the
|
|
|
|
|
tag the layers of Sofia software check whether they can handle the parameter
|
|
|
|
|
or should it just be passed to lower layers for processing.
|
|
|
|
|
|
|
|
|
|
There are some tags with special meaning:
|
|
|
|
|
- TAG_NULL() (synonymous to TAG_END()) end of tag list
|
|
|
|
|
- TAG_SKIP() empty tag item
|
|
|
|
|
- TAG_NEXT() tag item pointing to another tag list, ends the current tag list
|
|
|
|
|
- TAG_ANY() filter tag accepting any tag
|
|
|
|
|
- TAG_IF() conditional inclusion of tag item
|
|
|
|
|
|
|
|
|
|
The NUA functions can be called with a list of tagged values if they have
|
|
|
|
|
following parameters at the end of parameter list:
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
tag_type_t tag,
|
|
|
|
|
tag_value_t value,
|
|
|
|
|
...);
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The last tagged value on the parameter list must be TAG_NULL()
|
|
|
|
|
(or TAG_END(), synonym for TAG_NULL()).
|
|
|
|
|
|
|
|
|
|
Every tag has two versions: \n
|
|
|
|
|
NUTAG_<tagname> \n
|
|
|
|
|
which takes a value parameter and \n
|
|
|
|
|
NUTAG_<tagname>_REF \n
|
|
|
|
|
which takes a reference parameter. The latter is used with
|
|
|
|
|
tl_gets() function to retrieve tag values from tag list.
|
|
|
|
|
|
|
|
|
|
For SIP headers there exists also additional
|
|
|
|
|
version of tags: \n
|
|
|
|
|
SIPTAG_<tagname>_STR \n
|
|
|
|
|
This tag version takes a C-language character string as parameter.
|
|
|
|
|
The corresponding tag without _STR suffix takes a parsed value structure
|
|
|
|
|
as parameter.
|
|
|
|
|
|
|
|
|
|
The following is an example of call to NUA function containing tagged values:
|
|
|
|
|
@code
|
|
|
|
|
nua_unregister(op->op_handle,
|
|
|
|
|
TAG_IF(use_registrar, NUTAG_REGISTRAR(registrar)),
|
|
|
|
|
SIPTAG_CONTACT_STR("*"),
|
|
|
|
|
SIPTAG_EXPIRES_STR("0"),
|
|
|
|
|
TAG_NULL());
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
An application using NUA services must use tagged arguments for passing the
|
|
|
|
|
parameters to functions. See nua_invite() for discussion on how a SIP
|
|
|
|
|
message is constructed from the tags.
|
|
|
|
|
|
2007-08-06 19:24:10 +00:00
|
|
|
|
See documentation of <sofia-sip/su_tag.h> for more information of tags and the
|
2006-12-21 06:30:28 +00:00
|
|
|
|
module-specific documentation of each Sofia module for information of
|
|
|
|
|
tags specific for that module.
|
|
|
|
|
|
|
|
|
|
@subsection nua_debugandlogging Debugging and Logging
|
|
|
|
|
|
|
|
|
|
The modules of Sofia stack contain configurable debugging and logging
|
2007-08-06 19:24:10 +00:00
|
|
|
|
functionality based on the services defined in <sofia-sip/su_log.h>. The debugging
|
2006-12-21 06:30:28 +00:00
|
|
|
|
and logging details (for example level of details on output and output
|
|
|
|
|
file name) can be configured by environment variables, directives in
|
|
|
|
|
configuration files and compilation directives in the source files.
|
|
|
|
|
|
|
|
|
|
Examples of useful directives/ environment variables are:
|
|
|
|
|
- #SOFIA_DEBUG Default debug level (0..9)
|
|
|
|
|
- #NUA_DEBUG NUA debug level (0..9)
|
|
|
|
|
- #NTA_DEBUG Transaction engine debug level (0..9)
|
|
|
|
|
- #TPORT_DEBUG Transport event debug level (0..9)
|
|
|
|
|
- #TPORT_LOG If set, print out all parsed SIP messages on transport layer
|
|
|
|
|
- #TPORT_DUMP Filename for dumping unparsed messages from transport
|
|
|
|
|
|
|
|
|
|
The defined debug output levels are:
|
|
|
|
|
- 0 fatal errors, panic
|
|
|
|
|
- 1 critical errors, minimal progress at subsystem level
|
|
|
|
|
- 2 non-critical errors
|
|
|
|
|
- 3 warnings, progress messages
|
|
|
|
|
- 5 signaling protocol actions (incoming packets, ...)
|
|
|
|
|
- 7 media protocol actions (incoming packets, ...)
|
|
|
|
|
- 9 entering/exiting functions, very verbatim progress
|
|
|
|
|
|
|
|
|
|
An application using NUA services can also use the debugging and
|
|
|
|
|
logging services provided by the Sofia stack but it is not mandatory.
|
|
|
|
|
|
2007-08-06 19:24:10 +00:00
|
|
|
|
See documentation of <sofia-sip/su_log.h> for more information of debugging and
|
2006-12-21 06:30:28 +00:00
|
|
|
|
logging services.
|
|
|
|
|
|
|
|
|
|
@section nua_concepts NUA Concepts
|
|
|
|
|
|
|
|
|
|
@subsection nua_stackobject NUA Stack Object
|
|
|
|
|
|
|
|
|
|
Stack object represents an instance of SIP stack and media engine. It
|
|
|
|
|
contains reference to root object of that stack, user-agent-specific
|
|
|
|
|
settings, and reference to the SIP transaction engine, for example.
|
|
|
|
|
|
|
|
|
|
A NUA stack object is created by nua_create() function and deleted by
|
|
|
|
|
nua_destroy() function. The nua_shutdown() function is used to gracefully
|
|
|
|
|
release active the sessions by @b nua engine.
|
|
|
|
|
|
|
|
|
|
NUA stack object has type nua_t.
|
|
|
|
|
|
|
|
|
|
@subsection nua_operationhandle NUA Operation Handle
|
|
|
|
|
|
|
|
|
|
Operation handle represents an abstract SIP call/session. It contains
|
|
|
|
|
information of SIP dialog and media session, and state machine that
|
|
|
|
|
takes care of the call, high-level SDP offer-answer protocol, registration,
|
|
|
|
|
subscriptions, publications and simple SIP transactions. An operation
|
|
|
|
|
handle may contain list of tags used when SIP messages are created by
|
|
|
|
|
NUA (e.g. From and To headers).
|
|
|
|
|
|
|
|
|
|
An operation handle is created explicitly by the application using NUA
|
|
|
|
|
for sending messages (function nua_handle()) and by stack for incoming
|
|
|
|
|
calls/sessions (starting with INVITE or MESSAGE). The handle is destroyed
|
|
|
|
|
by the application using NUA (function nua_handle_destroy()).
|
|
|
|
|
|
|
|
|
|
Indication and response events are associated with an operation handle.
|
|
|
|
|
|
|
|
|
|
NUA operation handle has type nua_handle_t.
|
|
|
|
|
|
|
|
|
|
@subsection nua_stacktread Stack Thread and Message Passing Concepts
|
|
|
|
|
|
|
|
|
|
The stack thread is a separate thread from application that provides the
|
|
|
|
|
real-time protocol stack operations so that application thread can for
|
|
|
|
|
example block or redraw UI as it likes.
|
|
|
|
|
|
|
|
|
|
The communication between stack thread and application thread is asynchronous.
|
|
|
|
|
Most of the NUA API functions cause a send of a message to the stack thread
|
|
|
|
|
for processing and similarly when something happens in the stack thread it
|
|
|
|
|
sends a message to the application thread. The messages to the application
|
|
|
|
|
thread are delivered as invokes of the application callback function when
|
|
|
|
|
the application calls su_root_run() or su_root_step() function.
|
|
|
|
|
|
|
|
|
|
@subsection nua_sip_message SIP Message and Header Manipulation
|
|
|
|
|
|
|
|
|
|
SIP messages are manipulated with typesafe SIPTAG_ tags. There are
|
|
|
|
|
three versions of each SIP tag:
|
|
|
|
|
- SIPTAG_<tagname>() takes a parsed value as parameter.
|
|
|
|
|
- SIPTAG_<tagname>_STR() takes an unparsed string as parameter.
|
|
|
|
|
- SIPTAG_<tagname>_REF() takes a reference as parameter, is used
|
|
|
|
|
with tl_gets() function to retrieve tag values from tag list.
|
|
|
|
|
- SIPTAG_<tagname>__STR_REF() takes a reference as parameter, is used
|
|
|
|
|
with tl_gets() function to retrieve string tag values from tag list.
|
|
|
|
|
|
|
|
|
|
For example a header named "Example" would have tags names SIPTAG_EXAMPLE(),
|
|
|
|
|
SIPTAG_EXAMPLE_STR(), and SIPTAG_EXAMPLE_REF().
|
|
|
|
|
|
|
|
|
|
When tags are used in NUA calls the corresponding headers are added to
|
|
|
|
|
the message. In case the header can be present only once in a message
|
|
|
|
|
and there already exists a value for the header the value given by
|
|
|
|
|
tag replaces the existing header value. Passing tag value NULL has no
|
|
|
|
|
effect on headers. Passing tag value (void *)-1 removes corresponding
|
|
|
|
|
headers from the message.
|
|
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
|
|
- sending a SUBSCRIBE with @b Event: header and two @b Accept: headers:
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
nua_subscribe(nh,
|
|
|
|
|
SIPTAG_EVENT_STR("presence"),
|
|
|
|
|
SIPTAG_ACCEPT(accept1),
|
|
|
|
|
SIPTAG_ACCEPT(accept2),
|
|
|
|
|
TAG_END());
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
- fetching tag values when processing nua_r_subscribe event:
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
sip_accept_t *ac = NULL;
|
|
|
|
|
sip_event_t *o = NULL;
|
|
|
|
|
|
|
|
|
|
tl_gets(tl,
|
|
|
|
|
SIPTAG_EVENT_REF(o), /* _REF takes a reference! */
|
|
|
|
|
SIPTAG_ACCEPT_REF(ac),
|
|
|
|
|
TAG_END());
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section nua_tutorial SIP/NUA tutorial
|
|
|
|
|
|
|
|
|
|
This section describes basic usage scenarios of NUA/Sofia stack using
|
|
|
|
|
message sequence charts.
|
|
|
|
|
|
|
|
|
|
@subsection nua_outgoingcall Outgoing Call
|
|
|
|
|
|
|
|
|
|
@image latex SIP_outgoing_call.eps
|
|
|
|
|
|
|
|
|
|
@image html SIP_outgoing_call.gif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@subsection nua_incomingcall Incoming Call
|
|
|
|
|
|
|
|
|
|
@image latex SIP_incoming_call.eps
|
|
|
|
|
|
|
|
|
|
@image html SIP_incoming_call.gif
|
|
|
|
|
|
|
|
|
|
@subsection nua_basicoutgoingoperation Basic Outgoing Operation
|
|
|
|
|
|
|
|
|
|
@image latex SIP_basic_outgoing_operation.eps
|
|
|
|
|
|
|
|
|
|
@image html SIP_basic_outgoing_operation.gif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@subsection nua_basicincomingoperation Basic Incoming Operation
|
|
|
|
|
|
|
|
|
|
@image latex SIP_basic_incoming_operation.eps
|
|
|
|
|
|
|
|
|
|
@image html SIP_basic_incoming_operation.gif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@subsection nua_outgoingoperationwithauth Outgoing Operation with Authentication
|
|
|
|
|
|
|
|
|
|
@image latex SIP_outgoing_operation_with_auth.eps
|
|
|
|
|
|
|
|
|
|
@image html SIP_outgoing_operation_with_auth.gif
|
|
|
|
|
|
|
|
|
|
@section nua_simpleapplication Simple Application
|
|
|
|
|
|
|
|
|
|
The following sections will present code examples from a simple application
|
|
|
|
|
that uses services of NUA. The example is not complete but should present
|
|
|
|
|
all relevant details of the basic use of NUA.
|
|
|
|
|
|
2007-11-12 16:04:47 +00:00
|
|
|
|
On sourceforge.net there is available an example application
|
|
|
|
|
<a href="http://sourceforge.net/project/showfiles.php?group_id=143636&package_id=179933">
|
|
|
|
|
sofisip_cli.c</a> that can be studied for more complete example.
|
2006-12-21 06:30:28 +00:00
|
|
|
|
|
|
|
|
|
@subsection nua_datastructures Data Structures & Defines
|
|
|
|
|
|
|
|
|
|
An application using services of NUA normally defines data areas that are
|
|
|
|
|
used to store context information (i.e., "magic"). The types of pointers to
|
|
|
|
|
these context information areas are passed to NUA by defines.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
/* type for application context data */
|
|
|
|
|
typedef struct application application;
|
|
|
|
|
#define NUA_MAGIC_T application
|
|
|
|
|
|
|
|
|
|
/* type for operation context data */
|
|
|
|
|
typedef union oper_ctx_u oper_ctx_t;
|
|
|
|
|
#define NUA_HMAGIC_T oper_ctx_t
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The information area contents themselves can be defined as
|
|
|
|
|
C structures or unions:
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
/* example of application context information structure */
|
|
|
|
|
typedef struct application
|
|
|
|
|
{
|
|
|
|
|
su_home_t home[1]; /* memory home */
|
|
|
|
|
su_root_t *root; /* root object */
|
|
|
|
|
nua_t *nua; /* NUA stack object */
|
|
|
|
|
|
|
|
|
|
/* other data as needed ... */
|
|
|
|
|
} application;
|
|
|
|
|
|
|
|
|
|
/* Example of operation handle context information structure */
|
|
|
|
|
typedef union operation
|
|
|
|
|
{
|
|
|
|
|
nua_handle_t *handle; /* operation handle /
|
|
|
|
|
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
nua_handle_t *handle; /* operation handle /
|
|
|
|
|
... /* call-related information */
|
|
|
|
|
} call;
|
|
|
|
|
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
nua_handle_t *handle; /* operation handle /
|
|
|
|
|
... /* subscription-related information */
|
|
|
|
|
} subscription;
|
|
|
|
|
|
|
|
|
|
/* other data as needed ... */
|
|
|
|
|
|
|
|
|
|
} operation;
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
NUA stack object and handle are opaque to the application programmer.
|
|
|
|
|
Likewise, the application context is completely opaque to the NUA stack
|
|
|
|
|
module. NUA functions are passed a pointer, and that pointer is then
|
|
|
|
|
given back to the application within the callback parameters. In this
|
|
|
|
|
case the application context information structure is also used to
|
|
|
|
|
store a root object and memory home for memory handling. The application
|
|
|
|
|
context information also contains the NUA stack object information.
|
|
|
|
|
|
|
|
|
|
@subsection nua_initanddeinit Initialization and deinitialization
|
|
|
|
|
|
|
|
|
|
The following code is an example of application function that initializes
|
|
|
|
|
the system, enters the main loop for processing the messages, and, after
|
|
|
|
|
message processing is ended, deinitalizes the system.
|
|
|
|
|
|
|
|
|
|
If the application is not just responding to incoming SIP messages there must
|
|
|
|
|
also be means to send messages to NUA. This can be handled for example by
|
|
|
|
|
having a separate thread that calls NUA functions to send messages or by
|
|
|
|
|
having a socket connection to the application for sending commands to the
|
|
|
|
|
application (see documentation of su_wait_create() and su_root_register()).
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
/* Application context structure */
|
|
|
|
|
application appl[1] = {{{{(sizeof appl)}}}};
|
|
|
|
|
|
|
|
|
|
/* initialize system utilities */
|
|
|
|
|
su_init();
|
|
|
|
|
|
|
|
|
|
/* initialize memory handling */
|
|
|
|
|
su_home_init(appl->home);
|
|
|
|
|
|
|
|
|
|
/* initialize root object */
|
|
|
|
|
appl->root = su_root_create(appl);
|
|
|
|
|
|
|
|
|
|
if (appl->root != NULL) {
|
|
|
|
|
/* create NUA stack */
|
|
|
|
|
appl->nua = nua_create(appl->root,
|
|
|
|
|
app_callback,
|
|
|
|
|
appl,
|
|
|
|
|
/* tags as necessary ...*/
|
|
|
|
|
TAG_NULL());
|
|
|
|
|
|
|
|
|
|
if (appl->nua != NULL) {
|
|
|
|
|
/* set necessary parameters */
|
|
|
|
|
nua_set_params(appl->nua,
|
|
|
|
|
/* tags as necessary ... */
|
|
|
|
|
TAG_NULL());
|
|
|
|
|
|
|
|
|
|
/* enter main loop for processing of messages */
|
|
|
|
|
su_root_run(appl->root);
|
|
|
|
|
|
|
|
|
|
/* destroy NUA stack */
|
|
|
|
|
nua_destroy(appl->nua);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* deinit root object */
|
|
|
|
|
su_root_destroy(appl->root);
|
|
|
|
|
appl->root = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* deinitialize memory handling */
|
|
|
|
|
su_home_deinit(appl->home);
|
|
|
|
|
|
|
|
|
|
/* deinitialize system utilities */
|
|
|
|
|
su_deinit();
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_handlingevents Handling events
|
|
|
|
|
|
|
|
|
|
Handling of the events coming from NUA stack is done in the callback
|
|
|
|
|
function that is registered for NUA stack with the nua_create() function
|
|
|
|
|
when the application is initialized. The content of callback function is
|
|
|
|
|
in its simplest form just a switch/case statement that dispatches the
|
|
|
|
|
incoming events for processing to separate functions.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_callback(nua_event_t event,
|
|
|
|
|
int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
switch (event) {
|
|
|
|
|
case nua_i_invite:
|
|
|
|
|
app_i_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case nua_r_invite:
|
|
|
|
|
app_r_invite(status, phrase, nua, magic, nh, hmagic, sip, tags);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* and so on ... */
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* unknown event -> print out error message */
|
|
|
|
|
if (status > 100) {
|
|
|
|
|
printf("unknown event %d: %03d %s\n",
|
|
|
|
|
event,
|
|
|
|
|
status,
|
|
|
|
|
phrase);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
printf("unknown event %d\n", event);
|
|
|
|
|
}
|
|
|
|
|
tl_print(stdout, "", tags);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} /* app_callback */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_placeacall Place a call
|
|
|
|
|
|
|
|
|
|
The following three functions show an example of how a basic SIP
|
|
|
|
|
call is created.
|
|
|
|
|
|
|
|
|
|
The place_a_call() function creates an operation handle and invokes the
|
|
|
|
|
SIP INVITE method.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
operation *place_a_call(char const *name, url_t const *url)
|
|
|
|
|
{
|
|
|
|
|
operation *op;
|
|
|
|
|
sip_to_t *to;
|
|
|
|
|
|
|
|
|
|
/* create operation context information */
|
|
|
|
|
op = su_zalloc(appl->home, (sizeof *op));
|
|
|
|
|
if (!op)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Destination address */
|
|
|
|
|
to = sip_to_create(NULL, url);
|
|
|
|
|
if (!to)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
to->a_display = name;
|
|
|
|
|
|
|
|
|
|
/* create operation handle */
|
|
|
|
|
op->handle = nua_handle(appl->nua, op, SIPTAG_TO(to), TAG_END());
|
|
|
|
|
|
|
|
|
|
if (op->handle == NULL) {
|
|
|
|
|
printf("cannot create operation handle\n");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nua_invite(op->handle,
|
|
|
|
|
/* other tags as needed ... */
|
|
|
|
|
TAG_END());
|
|
|
|
|
|
|
|
|
|
} /* place_a_call */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The app_r_invite() function is called by callback function when response to
|
|
|
|
|
INVITE message is received. Here it is assumed that automatic acknowledge
|
|
|
|
|
is not enabled so ACK response must be sent explicitly.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_r_invite(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
if (status == 200) {
|
|
|
|
|
nua_ack(nh, TAG_END());
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
printf("response to INVITE: %03d %s\n", status, phrase);
|
|
|
|
|
}
|
|
|
|
|
} /* app_r_invite */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The nua_i_state event is sent (and app_i_state() function called by callback
|
|
|
|
|
function) when the call state changes (see @ref nua_uac_call_model
|
|
|
|
|
"client-side call model").
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_i_state(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
nua_callstate_t state = nua_callstate_init;
|
|
|
|
|
|
|
|
|
|
tl_gets(tags,
|
|
|
|
|
NUTAG_CALLSTATE_REF(state),
|
|
|
|
|
NUTAG__REF(state),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state = (nua_callstate_t)t->t_value;
|
|
|
|
|
|
|
|
|
|
printf("call %s\n", nua_callstate_name(state));
|
|
|
|
|
|
|
|
|
|
} /* app_i_state */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_receiveacall Receive a call
|
|
|
|
|
|
|
|
|
|
The app_i_invite() function is called by callback function when incoming
|
|
|
|
|
INVITE message is received. This example assumes that autoanswer is
|
|
|
|
|
not enabled so the response must be sent explicitly.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_i_invite(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
printf("incoming call\n");
|
|
|
|
|
|
|
|
|
|
nua_respond(nh, 200, "OK", SOA_USER_SDP(magic->sdp), TAG_END());
|
|
|
|
|
|
|
|
|
|
} /* app_i_invite */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The app_i_state() function is called by the callback function when call has
|
|
|
|
|
been successfully set up and the media has been activated.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_i_active(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
printf("call active\n");
|
|
|
|
|
|
|
|
|
|
} /* app_i_active */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_terminatingcall Terminating a call
|
|
|
|
|
|
|
|
|
|
The following three functions show an example of how a basic SIP
|
|
|
|
|
call is terminated.
|
|
|
|
|
|
|
|
|
|
The terminate_call() function sends the SIP BYE message.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void terminate_call(void)
|
|
|
|
|
{
|
|
|
|
|
nua_bye(op->handle, TAG_END());
|
|
|
|
|
|
|
|
|
|
} /* terminate call */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The app_r_bye() function is called by the callback function when answer to
|
|
|
|
|
the BYE message is received. The function destroys the call handle and
|
|
|
|
|
releases the memory allocated to operation context information.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_r_bye(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
if (status < 200)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
printf("call released\n");
|
|
|
|
|
|
|
|
|
|
/* release operation handle */
|
|
|
|
|
nua_handle_destroy(hmagic->handle);
|
|
|
|
|
op->handle = NULL;
|
|
|
|
|
|
|
|
|
|
/* release operation context information */
|
|
|
|
|
su_free(appl->home, hmagic);
|
|
|
|
|
|
|
|
|
|
} /* app_r_bye */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The app_i_bye() function is called by the callback function when an incoming
|
|
|
|
|
BYE message is received. The function destroys the call handle and releases
|
|
|
|
|
the memory allocated to operation context information.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_i_bye(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
printf("call released\n");
|
|
|
|
|
|
|
|
|
|
/* release operation handle */
|
|
|
|
|
nua_handle_destroy(hmagic->handle);
|
|
|
|
|
op->handle = NULL;
|
|
|
|
|
|
|
|
|
|
/* release operation context information */
|
|
|
|
|
su_free(appl->home, hmagic);
|
|
|
|
|
|
|
|
|
|
} /* app_i_bye */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_sendamessage Sending a message
|
|
|
|
|
|
|
|
|
|
The following functions show an example of how a SIP MESSAGE is sent.
|
|
|
|
|
|
|
|
|
|
The send_message() function sends the SIP MESSAGE.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void send_message(void)
|
|
|
|
|
{
|
|
|
|
|
op_t *op;
|
|
|
|
|
|
|
|
|
|
/* create operation context information */
|
|
|
|
|
op = su_zalloc(appl->home, sizeof(op_t));
|
|
|
|
|
if (op = NULL) {
|
|
|
|
|
printf("cannot create operation context information\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* how we create destination_address? */
|
|
|
|
|
|
|
|
|
|
/* create operation handle */
|
|
|
|
|
op->handle = nua_handle(appl->nua,
|
|
|
|
|
op,
|
|
|
|
|
NUTAG_URL(destination_address),
|
|
|
|
|
TAG_END());
|
|
|
|
|
|
|
|
|
|
if (op->handle == NULL) {
|
|
|
|
|
printf("cannot create operation handle\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* send MESSAGE */
|
|
|
|
|
nua_message(op->handle,
|
|
|
|
|
SIPTAG_CONTENT_TYPE_STR("text/plain"),
|
|
|
|
|
SIPTAG_PAYLOAD_STR("Hello, world!"),
|
|
|
|
|
/* other tags as needed ... */
|
|
|
|
|
TAG_END());
|
|
|
|
|
|
|
|
|
|
} /* send_message */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The app_r_message() function is called by the callback function when
|
|
|
|
|
answer to the MESSAGE is received.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_r_message(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
printf("response to MESSAGE: %03d %s\n", status, phrase);
|
|
|
|
|
} /* app_r_message */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_receivemessage Receiving a message
|
|
|
|
|
|
|
|
|
|
The following function shows an example of how a SIP MESSAGE is received.
|
|
|
|
|
|
|
|
|
|
The app_i_message() function is called by the callback function when
|
|
|
|
|
a SIP MESSAGE is received.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_i_message(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
printf("received MESSAGE: %03d %s\n", status, phrase);
|
|
|
|
|
|
|
|
|
|
printf("From: %s%s" URL_PRINT_FORMAT "\n",
|
|
|
|
|
sip->sip_from->a_display ? sip->sip_from->a_display : "",
|
|
|
|
|
sip->sip_from->a_display ? " " : "",
|
|
|
|
|
URL_PRINT_ARGS(sip->sip_from->a_url));
|
|
|
|
|
|
|
|
|
|
if (sip->sip_subject) {
|
|
|
|
|
printf("Subject: %s\n", sip->sip_subject->g_value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sip->sip_payload) {
|
|
|
|
|
fwrite(sip->sip_payload->pl_data, sip->sip_payload->pl_len, 1, stdout);
|
|
|
|
|
fputs("\n", stdout);
|
|
|
|
|
}
|
|
|
|
|
} /* app_i_message */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@subsection nua_notifier Creating a Presence Server
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
application_t *app;
|
|
|
|
|
operation_t *oper;
|
|
|
|
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
oper->app = app;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->nua = nua_create(ssip->s_root,
|
|
|
|
|
app_callback,
|
|
|
|
|
app,
|
|
|
|
|
TAG_NULL());
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
oper->handle = nua_handle(app->nua, app,
|
|
|
|
|
NUTAG_URL(to->a_url),
|
|
|
|
|
SIPTAG_TO(to),
|
|
|
|
|
ta_tags(ta));
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
nua_notifier(oper->handle,
|
|
|
|
|
SIPTAG_EXPIRES_STR("3600"),
|
|
|
|
|
SIPTAG_EVENT_STR("presence"),
|
|
|
|
|
SIPTAG_CONTENT_TYPE_STR("application/pidf-partial+xml"),
|
|
|
|
|
NUTAG_SUBSTATE(nua_substate_pending),
|
|
|
|
|
TAG_END());
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
After the nua_notifier object -- the presence server -- is created, an
|
|
|
|
|
event nua_r_notifier is returned. Status and phrase values of the
|
|
|
|
|
app_callback function indicate the success of the creation.
|
|
|
|
|
|
|
|
|
|
Authorization of an incoming subscription (to the local presence
|
|
|
|
|
server) can be handled in the callback function.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_callback(nua_event_t event,
|
|
|
|
|
int status, char const *phrase,
|
|
|
|
|
nua_t *nua, application_t *app,
|
|
|
|
|
nua_handle_t *nh, oper_t *op,
|
|
|
|
|
sip_t const *sip, tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
nea_sub_t *subscriber = NULL;
|
|
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
|
case nua_i_subscription:
|
|
|
|
|
tl_gets(tags,
|
|
|
|
|
NEATAG_SUB_REF(subscriber),
|
|
|
|
|
TAG_END());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nua_authorize(nua_substate_active);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@subsection nua_shutting_down Shutdown
|
|
|
|
|
|
|
|
|
|
The following functions show an example of how application terminates
|
|
|
|
|
the NUA stack.
|
|
|
|
|
|
|
|
|
|
The shutdown() function starts the termination.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void shutdown(void)
|
|
|
|
|
{
|
|
|
|
|
nua_shutdown(appl->nua);
|
|
|
|
|
|
|
|
|
|
} /* shutdown */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The app_r_shutdown() function is called by the callback function when NUA
|
|
|
|
|
stack termination is either finished or failed.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
void app_r_shutdown(int status,
|
|
|
|
|
char const *phrase,
|
|
|
|
|
nua_t *nua,
|
|
|
|
|
nua_magic_t *magic,
|
|
|
|
|
nua_handle_t *nh,
|
|
|
|
|
nua_hmagic_t *hmagic,
|
|
|
|
|
sip_t const *sip,
|
|
|
|
|
tagi_t tags[])
|
|
|
|
|
{
|
|
|
|
|
printf("shutdown: %d %s\n", status, phrase);
|
|
|
|
|
|
|
|
|
|
if (status < 200) {
|
|
|
|
|
/* shutdown in progress -> return */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* end the event loop. su_root_run() will return */
|
|
|
|
|
su_root_break(magic->root);
|
|
|
|
|
|
|
|
|
|
} /* app_r_shutdown */
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @page nua_call_model NUA Call Model
|
|
|
|
|
|
|
|
|
|
The NUA call follows a relatively simple state model presented below. The call
|
|
|
|
|
model is used to present changes in call: when media starts to flow, when
|
|
|
|
|
call is considered established, when call is terminated.
|
|
|
|
|
|
|
|
|
|
In the figure below, a simplified state diagram for a SIP call is presented.
|
|
|
|
|
After the call state has changes the application will receive an
|
|
|
|
|
#nua_i_state event indicating the change. The states in NUA call model are
|
|
|
|
|
represented by @e enum #nua_callstate, and the current value of state is
|
|
|
|
|
included as the tag NUTAG_CALLSTATE() with the #nua_i_state event.
|
|
|
|
|
|
|
|
|
|
The @RFC3264 SDP Offer/Answer negotiation status is also included in the
|
|
|
|
|
#nua_i_state event. The negotiation status includes the local SDP (in
|
|
|
|
|
SOATAG_LOCAL_SDP()) sent and flags indicating whether the local SDP was an
|
|
|
|
|
offer or answer (NUTAG_OFFER_SENT(), NUTAG_ANSWER_SENT()). Likewise, the
|
|
|
|
|
received remote SDP is included in tag SOATAG_REMOTE_SDP() and flags
|
|
|
|
|
indicating whether the remote SDP was an offer or an answer in tags
|
|
|
|
|
NUTAG_OFFER_RECV() or NUTAG_ANSWER_RECV(). SOATAG_ACTIVE_AUDIO() and
|
|
|
|
|
SOATAG_ACTIVE_VIDEO() are informational tags used to indicate what is the
|
|
|
|
|
status of these media.
|
|
|
|
|
|
|
|
|
|
The #nua_i_state event is not sent, however, if the change is invoked by
|
|
|
|
|
application calling API functions like nua_bye() and there is no change in
|
|
|
|
|
SDP offer/answer status.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
+---------------+
|
|
|
|
|
+------| INIT |-----+
|
|
|
|
|
INVITE/- | +---------------+ | INVITE/100
|
|
|
|
|
V |
|
|
|
|
|
+------------+ +------------+
|
|
|
|
|
+----| CALLING |--+ +---| RECEIVED |--+
|
|
|
|
|
| +------------+ | | +------------+ |
|
|
|
|
|
| | | | | |
|
|
|
|
|
| | 18X/- | | | -/18X |
|
|
|
|
|
| V | | V |
|
|
|
|
|
| +------------+ | | +------------+ |
|
|
|
|
|
|<---| PROCEEDING | | | | EARLY |->|
|
|
|
|
|
| +------------+ | | +------------+ | -/[3456]XX
|
|
|
|
|
| | | | | |
|
|
|
|
|
| | 2XX/- | 2XX/- | -/2XX | -/2XX | or
|
|
|
|
|
| V | | V |
|
|
|
|
|
| + - - - - - -+ | | +------------+ | CANCEL/200,487
|
|
|
|
|
| : COMPLETING :<-+ +-->| COMPLETE | |
|
|
|
|
|
| + - - - - - -+ +------------+ |
|
|
|
|
|
| | | |
|
|
|
|
|
| | -/ACK ACK/- | |
|
|
|
|
|
| | | |
|
|
|
|
|
| | | |
|
|
|
|
|
| | +---------------+ | |
|
|
|
|
|
| +----->| READY |<----+ |
|
|
|
|
|
| +---------------+ |
|
|
|
|
|
| | | |
|
|
|
|
|
| BYE/200 | | -/BYE |
|
|
|
|
|
| | | |
|
|
|
|
|
| | V |
|
|
|
|
|
| | +--------------+ |
|
|
|
|
|
| [3456]XX/ACK | | TERMINATING | |
|
|
|
|
|
| | +--------------+ |
|
|
|
|
|
| | | |
|
|
|
|
|
| | | [23456]XX/- |
|
|
|
|
|
| V V |
|
|
|
|
|
| +---------------+ |
|
|
|
|
|
+---------------->| TERMINATED |<--------------+
|
|
|
|
|
+---------------+
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The labels "input/output" along each transition indicates SIP messages
|
|
|
|
|
received from and sent to network, for instance, state transition
|
|
|
|
|
"INVITE/100" occurs when a SIP @b INVITE request is received, and it is
|
|
|
|
|
immediately returned a 100 (<i>Trying</i>) response. Label "2XX" means any
|
|
|
|
|
200-series response, e.g., <i>200 OK</i> or <i>202 Accepted</i>). Notation
|
|
|
|
|
"[3456]XX" means any final error response in 300, 400, 500, or 600
|
|
|
|
|
series. Label "18X" means any provisional response from 101 to 199, most
|
|
|
|
|
typically 180 (<i>Ringing</i>) or 183 (<i>Session Progress</i>).
|
|
|
|
|
|
|
|
|
|
@section nua_uac_call_model Detailed Client Call Model
|
|
|
|
|
|
|
|
|
|
The detailed call model at client side is presented below. This model does
|
|
|
|
|
not include the extensions like @b 100rel or @b UPDATE.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
+------------+
|
|
|
|
|
| INIT |
|
|
|
|
|
+------------+
|
|
|
|
|
|
|
|
|
|
|
(1) nua_invite/INVITE
|
|
|
|
|
|
|
|
|
|
|
V
|
|
|
|
|
+------------+
|
|
|
|
|
| |-----------------------------(6a)-----+
|
|
|
|
|
| |----+ nua_cancel |
|
|
|
|
|
+------| CALLING | (7a) /CANCEL |
|
|
|
|
|
| | |<---+ |
|
|
|
|
|
| | |----------------------+ |
|
|
|
|
|
| +------------+ | |
|
|
|
|
|
| | (8a) nua_bye |
|
|
|
|
|
| (2) 18X/- | /CANCEL |
|
|
|
|
|
| | | |
|
|
|
|
|
| V | |
|
|
|
|
|
| +------------+ | |
|
|
|
|
|
| | |-----------------------------(6b)---->|
|
|
|
|
|
| | |----+ nua_cancel | |
|
|
|
|
|
| | PROCEEDING | (7b) /CANCEL | |
|
|
|
|
|
| | |<---+ | |
|
|
|
|
|
| | |----------------------+ |
|
|
|
|
|
| +------------+ | |
|
|
|
|
|
| | | |
|
|
|
|
|
(3a) 2XX/- (3b) 2XX/- | (6) [3456]XX/ACK
|
|
|
|
|
| | | |
|
|
|
|
|
| V | |
|
|
|
|
|
| + - - - - - -+ | |
|
|
|
|
|
+----->: : | |
|
|
|
|
|
: COMPLETING :-------+ | |
|
|
|
|
|
+ - - -: : | | |
|
|
|
|
|
: + - - - - - -+ | | |
|
|
|
|
|
: | | | |
|
|
|
|
|
:<auto_ack> | | | |
|
|
|
|
|
:or nua_ack | <auto_ack> | | |
|
|
|
|
|
:and media | or nua_ack | nua_bye | |
|
|
|
|
|
(5) error (4) /ACK (9) /ACK+BYE (8b) nua_bye/BYE |
|
|
|
|
|
: /ACK+BYE | | | |
|
|
|
|
|
: V | V |
|
|
|
|
|
: +------------+ | +-------------+ |
|
|
|
|
|
: | | | | | |
|
|
|
|
|
: | READY | | | TERMINATING*| |
|
|
|
|
|
: | | | | | |
|
|
|
|
|
: +------------+ | +-------------+ |
|
|
|
|
|
: | | | |
|
|
|
|
|
: | (10) 2XX (11) 3XX 4XX |
|
|
|
|
|
: +-------------+ | | /BYE | 5XX 6XX |
|
|
|
|
|
: | | V V | /- |
|
|
|
|
|
+ - - >| TERMINATING |<-------------------------+ |
|
|
|
|
|
| | |
|
|
|
|
|
+-------------+ |
|
|
|
|
|
| |
|
|
|
|
|
(12) [23456]XX to BYE/- |
|
|
|
|
|
| |
|
|
|
|
|
V |
|
|
|
|
|
+------------+ |
|
|
|
|
|
| TERMINATED |<-------------------------------------+
|
|
|
|
|
+------------+
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The detailed description of state transitions on the client side is as
|
|
|
|
|
follows:
|
|
|
|
|
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>#</th>
|
|
|
|
|
<th>Previous state</th>
|
|
|
|
|
<th>Input</th>
|
|
|
|
|
<th>Output</th>
|
|
|
|
|
<th>Next state</th>
|
|
|
|
|
<th>Offer/ Answer</th>
|
|
|
|
|
<th align="left">Description</th>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr><td>C1</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>nua_invite()</td> <!-- input -->
|
|
|
|
|
<td>INVITE</td> <!-- output -->
|
|
|
|
|
<td>calling</td> <!-- next state -->
|
|
|
|
|
<td>Generate offer</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
Client application starts call be invoking nua_invite(). By default, stack runs
|
|
|
|
|
the initial offer/answer step and sends @b INVITE request with the SDP
|
|
|
|
|
offer.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C2</td>
|
|
|
|
|
<td>calling</td><td>18X</td><td>-</td><td>proceeding</td>
|
|
|
|
|
<td>(Save answer)</td>
|
|
|
|
|
<td>
|
|
|
|
|
Stack receives a 18X response (a provisional response between 101
|
|
|
|
|
and 199). It establishes an early dialog with server. If the provisional
|
|
|
|
|
response contains an SDP answer, a session with early media is
|
|
|
|
|
established. The caller can be listen to, for instance, ring tone or
|
|
|
|
|
announcements about call progress using the early media session.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C3a</td>
|
|
|
|
|
<td>calling</td><td rowspan="2">2XX</td>
|
|
|
|
|
<td rowspan="2">-</td><td rowspan="2">completing</td>
|
|
|
|
|
<td rowspan="2">Save answer</td>
|
|
|
|
|
<td rowspan="2">
|
|
|
|
|
Client receives a 2XX response (usually <i>200 OK</i>) indicating that
|
|
|
|
|
call has been accepted by the server. If there is an SDP session
|
|
|
|
|
description included with response, it is stored.
|
|
|
|
|
|
|
|
|
|
Unless the @ref NUTAG_AUTOACK() "auto-ack" mode is explicitly turned off
|
|
|
|
|
by application the client does not stay in @b completing state, but
|
|
|
|
|
proceeds immediately to next state transition.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C3b</td>
|
|
|
|
|
<td>proceeding</td></tr>
|
|
|
|
|
<tr><td>C4</td>
|
|
|
|
|
<td>completing</td>
|
|
|
|
|
<td>nua_ack() or<br>@ref NUTAG_AUTOACK() "auto-ack" </td>
|
|
|
|
|
<td>ACK</td><td>ready</td>
|
|
|
|
|
<td>Process answer</td>
|
|
|
|
|
<td>
|
|
|
|
|
Client sends an ACK request in this state transition. If the initial
|
|
|
|
|
offer was sent with INVITE, the answer must have been received by this
|
|
|
|
|
time, usually in the 2XX response. Client now completes the SDP
|
|
|
|
|
offer-answer exchange and activates the media.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C5</td>
|
|
|
|
|
<td>completing</td>
|
|
|
|
|
<td>nua_ack() or<br>@ref NUTAG_AUTOACK() "auto-ack" and<br> media error</td>
|
|
|
|
|
<td>ACK<br>BYE</td>
|
|
|
|
|
<td>terminating</td>
|
|
|
|
|
<td>Process answer</td>
|
|
|
|
|
<td>
|
2007-04-15 02:03:41 +00:00
|
|
|
|
If there was a failure in SDP negotiation or other failure with media,
|
2006-12-21 06:30:28 +00:00
|
|
|
|
the stack will automatically terminate the call. The BYE follows
|
2008-08-12 17:08:03 +00:00
|
|
|
|
immediately after the ACK.
|
2006-12-21 06:30:28 +00:00
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C6a</td>
|
|
|
|
|
<td>calling</td>
|
|
|
|
|
<td rowspan=2>3XX 4XX <br> 5XX 6XX</td>
|
|
|
|
|
<td rowspan=2>ACK*</td>
|
|
|
|
|
<td rowspan=2>terminated</td>
|
|
|
|
|
<td rowspan=2>-</td>
|
|
|
|
|
<td rowspan=2>
|
|
|
|
|
Call is terminated when client receives a final error response (from 300
|
|
|
|
|
to 699) to its INVITE request. In this case, the underlying transaction
|
|
|
|
|
engine takes care of sending ACK even when application-driven-ack mode is
|
|
|
|
|
requested by application.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C6b</td>
|
|
|
|
|
<td>proceeding</td>
|
|
|
|
|
</tr>
|
|
|
|
|
|
|
|
|
|
<tr><td>C7a</td>
|
|
|
|
|
<td>calling</td>
|
|
|
|
|
<td rowspan=2>nua_cancel()</td>
|
|
|
|
|
<td rowspan=2>CANCEL</td>
|
|
|
|
|
<td>calling</td>
|
|
|
|
|
<td rowspan=2>-</td>
|
|
|
|
|
<td rowspan=2>
|
|
|
|
|
Client can ask server to cancel the call attempt while in @b calling or
|
|
|
|
|
@b proceeding state. There is no direct call state transition caused by
|
|
|
|
|
nua_cancel(). The call state changes when the server returns a response.
|
|
|
|
|
After receiving a CANCEL request the server will usually return a <i>487
|
|
|
|
|
Request Terminated</i> response and call is terminated as in previous
|
|
|
|
|
item.
|
|
|
|
|
|
|
|
|
|
However, there is a race condition and the server can respond with a
|
|
|
|
|
succesful 2XX response before receiving CANCEL. In that case, the call is
|
|
|
|
|
established as usual. It is up to application to terminate the call with
|
|
|
|
|
nua_bye().
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C7b</td>
|
|
|
|
|
<td>proceeding</td>
|
|
|
|
|
<td>proceeding</td>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr><td>C8a</td>
|
|
|
|
|
<td>proceeding</td>
|
|
|
|
|
<td>nua_bye()</td>
|
|
|
|
|
<td>CANCEL</td>
|
|
|
|
|
<td rowspan=2>terminating*</td>
|
|
|
|
|
<td rowspan=2>-</td>
|
|
|
|
|
<td>
|
Merge up to the most recent sofia-sip darcs tree. Includes the following patches from darcs:
Tue Aug 21 09:38:59 EDT 2007 Pekka.Pessi@nokia.com
* tport_type_udp.c: checking error while checking that MSG_TRUNC works.
Shall I pull this patch? (1/43) [ynWvpxqadjk], or ? for help: y
Tue Aug 21 10:49:33 EDT 2007 Pekka.Pessi@nokia.com
* nua_params.c: NUTAG_SIPS_URL() now sets the handle target, too.
Problem reported by Jari Tenhunen.
Shall I pull this patch? (2/43) [ynWvpxqadjk], or ? for help: y
Thu Aug 23 11:22:42 EDT 2007 Pekka.Pessi@nokia.com
* nta.c: do not destroy INVITE transaction if it has been CANCELed
Handle gracefully cases where the INVITE transaction is destroyed
immediately after canceling it. The old behaviour was to left it up to the
application to ACK the final response returned to INVITE.
Thanks for Fabio Margarido for reporting this problem.
Shall I pull this patch? (3/43) [ynWvpxqadjk], or ? for help: y
Thu Aug 23 13:02:01 EDT 2007 Pekka.Pessi@nokia.com
* test_soa.c: added test with user SDP containing already rejected media
Shall I pull this patch? (4/43) [ynWvpxqadjk], or ? for help: y
Fri Aug 24 09:41:20 EDT 2007 Pekka.Pessi@nokia.com
* nta: added option for processing orphan responses matching with a dialog
The orphan responses matching with the dialog can now be processed by the
response callback.The dialog leg can be created with
NTATAG_RESPONSE_CALLBACK() or a response callback can be later bound to the
leg with nta_leg_bind_response().
This is practically useful only with 200 OK responses to the INVITE that are
retransmitted by the UAS. By default, the retransmission are catched by the
ACK transaction (which then retransmits the ACK request message). However,
after ACK transaction times out, the retransmitted 200 OK indicates most
probably that the ACK request messages do not reach UAS.
Partially fixes the sf.net bug #1750691 reported by Mikhail Zabaluev.
Shall I pull this patch? (5/43) [ynWvpxqadjk], or ? for help: y
Fri Aug 24 09:41:20 EDT 2007 Pekka.Pessi@nokia.com
UNDO: nta: added option for processing orphan responses matching with a dialog
The orphan responses matching with the dialog can now be processed by the
response callback.The dialog leg can be created with
NTATAG_RESPONSE_CALLBACK() or a response callback can be later bound to the
leg with nta_leg_bind_response().
This is practically useful only with 200 OK responses to the INVITE that are
retransmitted by the UAS. By default, the retransmission are catched by the
ACK transaction (which then retransmits the ACK request message). However,
after ACK transaction times out, the retransmitted 200 OK indicates most
probably that the ACK request messages do not reach UAS.
Partially fixes the sf.net bug #1750691 reported by Mikhail Zabaluev.
Shall I pull this patch? (6/43) [ynWvpxqadjk], or ? for help: y
Thu Aug 30 07:00:10 EDT 2007 Pekka.Pessi@nokia.com
* nta.c: disabled nta_msg_ackbye(). Fix for sf.net bug #1750691
Thanks for Mikhail Zabaluev for reporting this bug.
Shall I pull this patch? (7/43) [ynWvpxqadjk], or ? for help: y
Thu Aug 30 06:54:38 EDT 2007 Pekka.Pessi@nokia.com
* test_nua: added test for sf.net bug #1750691
Shall I pull this patch? (8/43) [ynWvpxqadjk], or ? for help: y
Thu Aug 30 07:03:45 EDT 2007 Pekka.Pessi@nokia.com
* test_nua: added test for nua_bye() sending CANCEL
Shall I pull this patch? (9/43) [ynWvpxqadjk], or ? for help: y
Fri Aug 31 12:08:09 EDT 2007 Pekka.Pessi@nokia.com
* url.c: fixed escaping of '/' %2F, ';' %3B and '=' %3D in URL path/params
Thanks for Fabio Margarido for reporting this bug.
Shall I pull this patch? (10/43) [ynWvpxqadjk], or ? for help: y
Mon Sep 3 10:14:55 EDT 2007 Pekka.Pessi@nokia.com
* url.c: do not un-escape %40 in URI parameters.
Do not unescape %2C, %3B, %3D, or %40 in URI parameters, nor
%2C, %2F, %3B, %3D, or %40 in URI path.
The @ sign can be ambiguous in the SIP URL, e.g.,
<sip:test.info;p=value@test.com>
can be parsed in two ways:
1) username contains test.info;param=value and host part has test.com
2) empty username, host part test.info, URI parameter p=value@test.com
Previously Sofia URL parser converted escaped '@' at signs (%40) in the URI
parameters to the unescaped form. The resulting URI could be ambiguous and
sometimes fail the syntax check if there was no '@' sign before the
unescaped one.
Thanks for Jan van den Bosch and Mikhail Zabaluev for reporting this bug.
Shall I pull this patch? (11/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 04:59:57 EDT 2007 Pekka.Pessi@nokia.com
* tport.c: fixed indenting, logging
Shall I pull this patch? (12/43) [ynWvpxqadjk], or ? for help: y
Fri Jul 13 12:47:33 EDT 2007 Pekka.Pessi@nokia.com
* nua/test_proxy.h, nua/test_proxy.c: added support for multiple domains
Each domain has its own registrar and authentication module.
Shall I pull this patch? (13/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 11:19:33 EDT 2007 Pekka.Pessi@nokia.com
* test_ops.c: added timestamp to event logging
Shall I pull this patch? (14/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 11:20:12 EDT 2007 Pekka.Pessi@nokia.com
* test_nua: fixed timing problems in testing.
Shall I pull this patch? (15/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 11:31:04 EDT 2007 Pekka.Pessi@nokia.com
* test_ops.c: reduce su_root_step() delay to 0.1 seconds
Shall I pull this patch? (16/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 11:31:22 EDT 2007 Pekka.Pessi@nokia.com
* test_register.c: fixed timing problem
Shall I pull this patch? (17/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 17:03:46 EDT 2007 Pekka.Pessi@nokia.com
* test_100rel.c: fixed timing problems resulting in events being reordered
Shall I pull this patch? (18/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:40:53 EDT 2007 Pekka.Pessi@nokia.com
* nua (test_init.c, test_register.c): using test_proxy domains
Shall I pull this patch? (19/43) [ynWvpxqadjk], or ? for help: y
Thu Aug 23 12:12:32 EDT 2007 Pekka.Pessi@nokia.com
* test_soa.c: added cleanup code
Shall I pull this patch? (20/43) [ynWvpxqadjk], or ? for help: y
Fri Aug 24 09:35:35 EDT 2007 Pekka.Pessi@nokia.com
* nta.c: increase lifetime of ACK transaction from T4 to T1 x 64
nta.c creates a ACK transaction in order to restransmit ACK requests when
ever a retransmitted 2XX response to INVITE is received. The UAS retransmits
the 2XX responses for 64 x T1 (32 second by default).
Partially fixes the sf.net bug #1750691 reported by Mikhail Zabaluev.
Shall I pull this patch? (21/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 10:21:04 EDT 2007 Pekka.Pessi@nokia.com
* Makefile.am: generating libsofia-sip-ua/docs/Doxyfile.rfc before making manpages
Shall I pull this patch? (22/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:05:33 EDT 2007 Pekka.Pessi@nokia.com
* sofia-sip/tport_tag.h: added TPTAG_KEEPALIVE(), TPTAG_PINGPONG(), TPTAG_PONG2PING()
Shall I pull this patch? (23/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:09:06 EDT 2007 Pekka.Pessi@nokia.com
* tport: added ping-pong keepalive on TCP. replaced single tick with connection-specific timer
Now detecting closed connections on TLS, too.
Added tests for idle timeout, receive timeout, ping-pong timeout.
Shall I pull this patch? (24/43) [ynWvpxqadjk], or ? for help: y
Fri Jul 6 10:19:32 EDT 2007 Pekka.Pessi@nokia.com
* nta.c: added nta_incoming_received()
Shall I pull this patch? (25/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 11:29:56 EDT 2007 Pekka.Pessi@nokia.com
* nua_session.c: delay transition to ready when O/A is incomplete
Delay sending ACK and subsequent transition of call to the ready state when
the 200 OK response to the INVITE is received if the SDP Offer/Answer
exchange using UPDATE/PRACK was still incomplete.
Previously, if the O/A using UPDATE or PRACK was incomplete and an 200 OK
was received, the call setup logic regarded this as a fatal error and
terminated the call.
Thanks for Mike Jerris for detecting and reporting this bug.
Shall I pull this patch? (26/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:22:46 EDT 2007 Pekka.Pessi@nokia.com
* test_call_reject.c: testing Retry-After
Shall I pull this patch? (27/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:42:51 EDT 2007 Pekka.Pessi@nokia.com
* test_nua: using rudimentary outbound support in B's proxy.
Shall I pull this patch? (28/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:48:33 EDT 2007 Pekka.Pessi@nokia.com
* nua_register.c: added some logging to nua_register_connection_closed()
Shall I pull this patch? (29/43) [ynWvpxqadjk], or ? for help: y
Wed Jul 25 12:43:57 EDT 2007 Pekka.Pessi@nokia.com
* test_nua: using AUTHTAG_MAX_NCOUNT(1) for Mr. C
C is now challenged every time.
Shall I pull this patch? (30/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 11:05:19 EDT 2007 Pekka.Pessi@nokia.com
* nua/test_100rel.c: fixed timing problem re response to PRACK and ACK
Shall I pull this patch? (31/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 06:02:50 EDT 2007 Mikhail Zabaluev <mikhail.zabaluev@nokia.com>
* DIST_SUBDIRS must include everything unconditionally
Shall I pull this patch? (32/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 13:53:04 EDT 2007 Pekka.Pessi@nokia.com
* test_soa.c: silenced warnings
Shall I pull this patch? (33/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 16:59:48 EDT 2007 Pekka.Pessi@nokia.com
* nua: refactored dialog refresh code
Shall I pull this patch? (34/43) [ynWvpxqadjk], or ? for help: y
Mon Jul 23 16:59:48 EDT 2007 Pekka.Pessi@nokia.com
UNDO: nua: refactored dialog refresh code
Shall I pull this patch? (35/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 12:01:25 EDT 2007 Pekka.Pessi@nokia.com
* nua_dialog.[hc]: renamed functions setting refresh interval
Shall I pull this patch? (36/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 12:15:03 EDT 2007 Pekka.Pessi@nokia.com
* nua_dialog.[hc], nua_stack.c: added nua_dialog_repeat_shutdown()
Shall I pull this patch? (37/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 12:19:20 EDT 2007 Pekka.Pessi@nokia.com
* nua_dialog.h: renamed nua_remote_t as nua_dialog_peer_info_t
Shall I pull this patch? (38/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 12:23:04 EDT 2007 Pekka.Pessi@nokia.com
* nua_stack.c: added timer to client request in order to implement Retry-After
Shall I pull this patch? (39/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 12:33:53 EDT 2007 Pekka.Pessi@nokia.com
* nua: added backpointers to nua_dialog_usage_t and nua_dialog_state_t
Shall I pull this patch? (40/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 13:56:48 EDT 2007 Pekka.Pessi@nokia.com
* test_nua.c: abort() in timeout alarm function if -a is given
Shall I pull this patch? (41/43) [ynWvpxqadjk], or ? for help: y
Thu Sep 6 17:13:18 EDT 2007 Pekka.Pessi@nokia.com
* nua_subnotref.c: include SIPTAG_EVENT() in the nua_i_notify tag list
Shall I pull this patch? (42/43) [ynWvpxqadjk], or ? for help: y
Mon Sep 10 12:27:53 EDT 2007 Pekka.Pessi@nokia.com
* nua: save Contact from target refresh request or response.
Save the Contact header which the application has added to the target
refresh requests or responses and use the saved contact in subsequent target
refresh requests or responses.
Previously the application had no way of specifying the Contact included in
the automatic responses to target refresh requests.
Thanks for Anthony Minessale for reporting this problem.
Shall I pull this patch? (43/43) [ynWvpxqadjk], or ? for help: y
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@5692 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-09-10 20:45:25 +00:00
|
|
|
|
The call cannot be terminated with BYE before the dialog is established
|
|
|
|
|
with a non-100 preliminary response. So, instead of a @b BYE, stack sends
|
|
|
|
|
a @b CANCEL request, and enters terminating state.
|
2006-12-21 06:30:28 +00:00
|
|
|
|
|
|
|
|
|
However, there is a race condition and the server can respond with a
|
|
|
|
|
succesful 2XX response before receiving CANCEL. If the server responds with
|
|
|
|
|
a 2XX response, the nua will automatically send a BYE request asking server
|
|
|
|
|
to terminate the call.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C8b</td>
|
|
|
|
|
<td>proceeding</td>
|
|
|
|
|
<td>nua_bye()</td>
|
|
|
|
|
<td>BYE</td>
|
|
|
|
|
<td>
|
|
|
|
|
Even an early session can be terminated after entering @b proceeding
|
|
|
|
|
state with nua_bye(). Stack sends a @b BYE request, and enters
|
|
|
|
|
terminating state. Unlike @b CANCEL, @b BYE affects only one fork.
|
|
|
|
|
|
|
|
|
|
However, there is a race condition and the server can respond with a
|
|
|
|
|
succesful 2XX response before receiving BYE. If the server responds with
|
|
|
|
|
a 2XX response, the nua will automatically send a BYE request asking server
|
|
|
|
|
to terminate the call.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>C9</td>
|
|
|
|
|
<td>completing</td><td>nua_bye()</td><td>ACK<br>BYE</td><td>terminating</td>
|
|
|
|
|
<td>-</td>
|
|
|
|
|
<td>
|
|
|
|
|
If the stack is in @b completing state (it has already
|
|
|
|
|
received 2XX response), it will have to @b ACK the final response, too.
|
|
|
|
|
</td></tr>
|
|
|
|
|
|
|
|
|
|
<tr><td>C10</td>
|
|
|
|
|
<td>terminating*</td>
|
|
|
|
|
<td>2XX<br>to INVITE</td>
|
|
|
|
|
<td>BYE</td>
|
|
|
|
|
<td>terminating</td>
|
|
|
|
|
<td>-</td>
|
|
|
|
|
<td>
|
|
|
|
|
There is a race condition between @b BYE and @b INVITE. The call may have
|
|
|
|
|
been re-established with @b INVITE after @b BYE was processed. @b BYE is
|
|
|
|
|
re-sent and call state transitions to normal terminating state.
|
|
|
|
|
</td></tr>
|
|
|
|
|
|
|
|
|
|
<tr><td>C11</td>
|
|
|
|
|
<td>terminating*</td>
|
|
|
|
|
<td>3XX 4XX<br>5XX 6XX<br>to INVITE</td>
|
|
|
|
|
<td>BYE</td>
|
|
|
|
|
<td>terminating</td>
|
|
|
|
|
<td>-</td>
|
|
|
|
|
<td>
|
|
|
|
|
The @b INVITE transaction is completed without a call being created. The
|
|
|
|
|
call state transitions to normal terminating state.
|
|
|
|
|
</td></tr>
|
|
|
|
|
|
|
|
|
|
<tr><td>C12</td>
|
|
|
|
|
<td>terminating</td>
|
|
|
|
|
<td>3XX 4XX<br>5XX 6XX<br>to BYE</td>
|
|
|
|
|
<td>-</td>
|
|
|
|
|
<td>terminated</td>
|
|
|
|
|
<td>-</td>
|
|
|
|
|
<td>
|
|
|
|
|
Call is terminated when the final response to the BYE is received.
|
|
|
|
|
</td></tr>
|
|
|
|
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
@section nua_uas_call_model Detailed Server-Side Call Model
|
|
|
|
|
|
|
|
|
|
The detailed call model at server side (UAS) is presented below. This model
|
|
|
|
|
does not include the extensions like @b 100rel or @b UPDATE.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
|
|
|
|
|
+----------------------------------+
|
|
|
|
|
| INIT |
|
|
|
|
|
+----------------------------------+
|
|
|
|
|
| : :
|
|
|
|
|
| : :
|
|
|
|
|
(1) INVITE/100 (2b) INVITE/18X (3c) INVITE/2XX
|
|
|
|
|
| : :
|
|
|
|
|
| : :
|
|
|
|
|
V : :
|
|
|
|
|
+------------+ : :
|
|
|
|
|
+--------------------| | : :
|
|
|
|
|
| | RECEIVED |--------------+ :
|
|
|
|
|
| +---------------| | : | :
|
|
|
|
|
| | +------------+ : | :
|
|
|
|
|
| | | : | :
|
2007-04-15 02:03:41 +00:00
|
|
|
|
| | nua_respond/18X (2a) : | :
|
2006-12-21 06:30:28 +00:00
|
|
|
|
| | | : | :
|
|
|
|
|
| | V V | :
|
|
|
|
|
| | +------------+ | :
|
|
|
|
|
|<------------------------------| | | :
|
|
|
|
|
| |<-------------------------| EARLY | | :
|
|
|
|
|
| | +----------| | | :
|
|
|
|
|
| | | +------------+ | :
|
|
|
|
|
| nua_respond/ | | | :
|
|
|
|
|
(6) /[3456]XX | nua_respond/2XX (3b) (3a) :
|
|
|
|
|
| | | | | :
|
|
|
|
|
| | | V V V
|
|
|
|
|
| | | +-------------+
|
|
|
|
|
| | | | |
|
|
|
|
|
| | | +-----| COMPLETED |- - +
|
|
|
|
|
| | | | | | :
|
|
|
|
|
| | | | +-------------+ :
|
|
|
|
|
| | | | | :
|
|
|
|
|
| | | | (4) ACK/- :
|
|
|
|
|
| | | | | :
|
|
|
|
|
| | | | V :
|
|
|
|
|
| | | | +-------------+ :
|
|
|
|
|
| | | | | | :
|
|
|
|
|
| | | | | READY | :
|
|
|
|
|
| | | | | | :
|
|
|
|
|
| | | | +-------------+ :
|
|
|
|
|
| | | | :
|
|
|
|
|
| (7) CANCEL/487 (8) BYE/487 (9) BYE/200 (5) timeout
|
|
|
|
|
| | | | : /BYE
|
|
|
|
|
| | | | +-------------+ :
|
|
|
|
|
| | | | | TERMINATING |<- -+
|
|
|
|
|
| | | | +-------------+
|
|
|
|
|
| | | | |
|
|
|
|
|
| | | | | [23456]XX/-
|
|
|
|
|
| | | | |
|
|
|
|
|
| | | | V
|
|
|
|
|
| V V V +-------------+
|
|
|
|
|
+---------------------------------------->| TERMINATED |
|
|
|
|
|
+-------------+
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The detailed description of state transitions on the server side is as
|
|
|
|
|
follows:
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>#</th>
|
|
|
|
|
<th>Previous state</th>
|
|
|
|
|
<th>Input</th>
|
|
|
|
|
<th>Output</th>
|
|
|
|
|
<th>Next state</th>
|
|
|
|
|
<th>Offer/ Answer</th>
|
|
|
|
|
<th align="left">Description</th>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr><td>S1</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>INVITE</td> <!-- input -->
|
|
|
|
|
<td>100 Trying</td> <!-- output -->
|
|
|
|
|
<td>received</td> <!-- next state -->
|
|
|
|
|
<td>Save offer</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
When a @b INVITE request for a new call is received, the server creates a
|
|
|
|
|
fresh call handle for it, responds to the client with <i>100 Trying</i>
|
|
|
|
|
and enters in the @b received state by default. It saves the possible SDP
|
|
|
|
|
offer included in @b INVITE and passes it to the application.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S2a</td> <!-- transition -->
|
|
|
|
|
<td>received</td> <!-- previous state -->
|
|
|
|
|
<td>nua_respond()</td> <!-- input -->
|
|
|
|
|
<td>18X</td> <!-- output -->
|
|
|
|
|
<td rowspan=2>early</td> <!-- next state -->
|
|
|
|
|
<td>(Generate early answer)</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
When server returns a preliminary response for the initial @b INVITE request,
|
|
|
|
|
a early dialog is created. The server can also send an SDP answer with
|
|
|
|
|
the preliminary answer and establish an early session, too. It can use
|
|
|
|
|
the early session to send early media, e.g., ringing tone and
|
|
|
|
|
announcements towards the client.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S2b</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>INVITE and <!-- input -->
|
|
|
|
|
@ref NUTAG_AUTOALERT() "auto-alert"</td>
|
|
|
|
|
<td>180 Ringing</td> <!-- output -->
|
|
|
|
|
<td>Save offer (and
|
|
|
|
|
generate early answer)</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
When @ref NUTAG_AUTOALERT() "auto-alert" option is enabled, stack sends
|
|
|
|
|
180 Ringing immediately after receiving INVITE and enters @b early state.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S3a</td> <!-- transition -->
|
|
|
|
|
<td>received</td> <!-- previous state -->
|
|
|
|
|
<td rowspan=2>nua_respond()</td> <!-- input -->
|
|
|
|
|
<td rowspan=2>2XX</td> <!-- output -->
|
|
|
|
|
<td rowspan=3>completed</td> <!-- next state -->
|
|
|
|
|
<td rowspan=2>Generate answer</td> <!-- offer/answer -->
|
|
|
|
|
<td rowspan=2>
|
|
|
|
|
When the server sends a 2XX response towards the client, it accepts the
|
|
|
|
|
call. The @b INVITE transaction is now considered complete but unconfirmed
|
|
|
|
|
at the server side. If the offer was sent in @b INVITE request, the answer
|
|
|
|
|
should be included in the 2XX response.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S3b</td> <!-- transition -->
|
|
|
|
|
<td>early</td> <!-- previous state -->
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S3c</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>INVITE and @ref NUTAG_AUTOANSWER() "auto-answer"
|
|
|
|
|
</td> <!-- input -->
|
|
|
|
|
<td>200 OK</td> <!-- output -->
|
|
|
|
|
<td>Save offer and
|
|
|
|
|
<br>generate answer</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
When @ref NUTAG_AUTOANSWER() "auto-answer" option is enabled, stack send
|
|
|
|
|
200 OK immediately after receiving INVITE and enters @b completed state.
|
|
|
|
|
</td></tr>
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S4</td> <!-- transition -->
|
|
|
|
|
<td>completed</td> <!-- previous state -->
|
|
|
|
|
<td>ACK</td> <!-- input -->
|
|
|
|
|
<td>-</td> <!-- output -->
|
|
|
|
|
<td>ready</td> <!-- next state -->
|
|
|
|
|
<td>-</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
The ready state is entered at server side after receiving @b ACK request
|
|
|
|
|
from client, indicating that the client have received server's 2XX
|
|
|
|
|
response. The call is ready, the @b INVITE transaction is confirmed.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S5td> <!-- transition -->
|
|
|
|
|
<td>completed</td> <!-- previous state -->
|
|
|
|
|
<td>timeout</td> <!-- input -->
|
|
|
|
|
<td>BYE</td> <!-- output -->
|
|
|
|
|
<td>terminating</td> <!-- next state -->
|
|
|
|
|
<td>-</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
If the server does not receive an @b ACK request in timely fashion, it will
|
|
|
|
|
terminate the call by sending a @b BYE request to client.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S6a</td> <!-- transition -->
|
|
|
|
|
<td>received</td> <!-- previous state -->
|
|
|
|
|
<td rowspan=2>nua_respond()</td> <!-- input -->
|
|
|
|
|
<td rowspan=2>3XX 4XX<br>5XX 6XX</td><!-- output -->
|
|
|
|
|
<td rowspan=2>terminated</td> <!-- next state -->
|
|
|
|
|
<td rowspan=2>-</td> <!-- offer/answer -->
|
|
|
|
|
<td rowspan=2>
|
|
|
|
|
The server can reject the call by sending a 3XX, 4XX, 5XX, or 6XX response
|
|
|
|
|
towards the client. The underlying transaction engine takes care of
|
|
|
|
|
retransmitting the response when needed. It consumes the ACK response
|
|
|
|
|
sent by the client, too.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S6b</td> <!-- transition -->
|
|
|
|
|
<td>early</td> <!-- previous state -->
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S7a</td> <!-- transition -->
|
|
|
|
|
<td>received</td> <!-- previous state -->
|
|
|
|
|
<td rowspan=2>CANCEL</td> <!-- input -->
|
|
|
|
|
<td rowspan=2>487 Request terminated</td><!-- output -->
|
|
|
|
|
<td rowspan=2>terminated</td> <!-- next state -->
|
|
|
|
|
<td rowspan=2>-</td> <!-- offer/answer -->
|
|
|
|
|
<td rowspan=2>
|
|
|
|
|
The client can cancel the call attempt before it is completed with a @b
|
|
|
|
|
CANCEL request. Server returns a <i>200 OK</i> response to @b CANCEL and
|
|
|
|
|
a <i>487 Request Terminated</i> response to the @b INVITE transaction and
|
|
|
|
|
the call is terminated.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S7b</td> <!-- transition -->
|
|
|
|
|
<td>early</td> <!-- previous state -->
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S8</td> <!-- transition -->
|
|
|
|
|
<td>early</td> <!-- previous state -->
|
|
|
|
|
<td>BYE</td> <!-- input -->
|
|
|
|
|
<td>487 to INVITE<br>
|
|
|
|
|
200 to BYE</td> <!-- output -->
|
|
|
|
|
<td>terminated</td> <!-- next state -->
|
|
|
|
|
<td>-</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
The client can terminate an early session with a @b BYE request, too. Like
|
|
|
|
|
in the @b CANCEL case above, the server will terminate call immediately,
|
|
|
|
|
return a <i>200 OK</i> response to @b BYE and a <i>487 Request
|
|
|
|
|
Terminated</i> response to the @b INVITE transaction.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S9</td> <!-- transition -->
|
|
|
|
|
<td>completed</td> <!-- previous state -->
|
|
|
|
|
<td>BYE</td> <!-- input -->
|
|
|
|
|
<td>200 to BYE</td> <!-- output -->
|
|
|
|
|
<td>terminated</td> <!-- next state -->
|
|
|
|
|
<td>-</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
The client can terminate a completed dialog with a @b BYE request. Server
|
|
|
|
|
terminates call immediately, returns a <i>200 OK</i> response to @b BYE
|
|
|
|
|
and lets the underlying transaction engine to take care of consuming @b
|
|
|
|
|
ACK.
|
|
|
|
|
</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
@section nua_3pcc_call_model Third Party Call Control
|
|
|
|
|
|
|
|
|
|
There is an alternative offer-answer model for third party call control
|
|
|
|
|
(3pcc). The call setup involves a 3rd party, client C, which sends initial
|
|
|
|
|
INVITE to server A without SDP. The call setup looks perfectly ordinary to
|
|
|
|
|
server B, however.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
A C B
|
|
|
|
|
| | |
|
|
|
|
|
|<-------INVITE---------| |
|
|
|
|
|
| | |
|
|
|
|
|
| | |
|
|
|
|
|
|------200 (offer)----->| |
|
|
|
|
|
| |----INVITE (offer)---->|
|
|
|
|
|
| | |
|
|
|
|
|
| | |
|
|
|
|
|
| |<-----200 (answer)-----|
|
|
|
|
|
|<-----ACK (answer)-----| |
|
|
|
|
|
| | |
|
|
|
|
|
| |----------ACK--------->|
|
|
|
|
|
| | |
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The modifications to the call model affect mainly offer-answer model.
|
|
|
|
|
The detailed description of state transitions for 3pcc on the server side is as
|
|
|
|
|
follows:
|
|
|
|
|
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>#</th>
|
|
|
|
|
<th>Previous state</th>
|
|
|
|
|
<th>Input</th>
|
|
|
|
|
<th>Output</th>
|
|
|
|
|
<th>Next state</th>
|
|
|
|
|
<th>Offer/ Answer</th>
|
|
|
|
|
<th align="left">Description</th>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr><td>S1'</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>INVITE</td> <!-- input -->
|
|
|
|
|
<td>100 Trying</td> <!-- output -->
|
|
|
|
|
<td>received</td> <!-- next state -->
|
|
|
|
|
<td>-</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
There is no SDP to save.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S2b'</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>INVITE and <!-- input -->
|
|
|
|
|
@ref NUTAG_AUTOALERT() "auto-alert"</td>
|
|
|
|
|
<td>180 Ringing</td> <!-- output -->
|
|
|
|
|
<td>early</td> <!-- next state -->
|
|
|
|
|
<td>-</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
There is no SDP to save.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S3a'</td> <!-- transition -->
|
|
|
|
|
<td>early</td> <!-- previous state -->
|
|
|
|
|
<td rowspan=2>nua_respond()</td> <!-- input -->
|
|
|
|
|
<td rowspan=2>2XX</td> <!-- output -->
|
|
|
|
|
<td rowspan=3>completed</td> <!-- next state -->
|
|
|
|
|
<td rowspan=3>Generate offer</td> <!-- offer/answer -->
|
|
|
|
|
<td rowspan=3>
|
|
|
|
|
The offer is sent in 200 OK.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S3b'</td> <!-- transition -->
|
|
|
|
|
<td>received</td> <!-- previous state -->
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S3c'</td> <!-- transition -->
|
|
|
|
|
<td>init</td> <!-- previous state -->
|
|
|
|
|
<td>INVITE and <!-- input -->
|
|
|
|
|
@ref NUTAG_AUTOANSWER() "auto-answer"</td>
|
|
|
|
|
<td>200 OK</td> <!-- output -->
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S4'</td> <!-- transition -->
|
|
|
|
|
<td>completed</td> <!-- previous state -->
|
|
|
|
|
<td>ACK</td> <!-- input -->
|
|
|
|
|
<td>-</td> <!-- output -->
|
|
|
|
|
<td>ready</td> <!-- next state -->
|
|
|
|
|
<td>Save and process answer</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
The answer is processed and media activated after receiving @b ACK.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>S9b'</td> <!-- transition -->
|
|
|
|
|
<td>completed</td> <!-- previous state -->
|
|
|
|
|
<td>ACK and O/A error</td> <!-- input -->
|
|
|
|
|
<td>BYE</td> <!-- output -->
|
|
|
|
|
<td>terminating</td> <!-- next state -->
|
|
|
|
|
<td>Save and process answer</td> <!-- offer/answer -->
|
|
|
|
|
<td>
|
|
|
|
|
If the offer/answer negotiation ends in error after the server receives
|
|
|
|
|
answer in @b ACK request, the server will have to terminate call by
|
|
|
|
|
sending a @b BYE request.
|
|
|
|
|
</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@section nua_terminate_call_model Model for Modifying and Terminating Call
|
|
|
|
|
|
|
|
|
|
After the SIP session has been established, it can be further modified by @b
|
|
|
|
|
INVITE transactions, initiated by either the original client or the original
|
|
|
|
|
server. These so-called re-INVITE transactions can be used to upgrade
|
|
|
|
|
session (add new media to it), put the session on hold or resume a held
|
|
|
|
|
call.
|
|
|
|
|
|
|
|
|
|
A session can be terminated with a @b BYE request at any time.
|
|
|
|
|
|
|
|
|
|
If any in-dialog request (including re-INVITE) fails with certain response
|
|
|
|
|
code, the session can be considered terminated, too. These response codes
|
|
|
|
|
are documented with sip_response_terminates_dialog(). In some cases, the
|
|
|
|
|
session should be terminated gracefully by sending a @b BYE request after
|
|
|
|
|
the failed requests.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
+-------------------------------------------------------------+
|
|
|
|
|
| READY |
|
|
|
|
|
+-------------------------------------------------------------+
|
|
|
|
|
| | | |
|
|
|
|
|
| | | |
|
|
|
|
|
(1) BYE/200 (2) nua_bye/BYE (4) graceful/BYE (5) fatal/-
|
|
|
|
|
| | | |
|
|
|
|
|
| V V |
|
|
|
|
|
| +-----------------------------+ |
|
|
|
|
|
| | TERMINATING | |
|
|
|
|
|
| +-----------------------------+ |
|
|
|
|
|
| | |
|
|
|
|
|
| (3) [23456]XX/- |
|
|
|
|
|
| | |
|
|
|
|
|
V V V
|
|
|
|
|
+-------------------------------------------------------------+
|
|
|
|
|
| TERMINATED |
|
|
|
|
|
+-------------------------------------------------------------+
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
The detailed description of state transitions while call is terminated is as
|
|
|
|
|
follows:
|
|
|
|
|
<table>
|
|
|
|
|
<tr><th>#</th>
|
|
|
|
|
<th>Previous state</th>
|
|
|
|
|
<th>Input</th>
|
|
|
|
|
<th>Output</th>
|
|
|
|
|
<th>Next state</th>
|
|
|
|
|
<th align="left">Description</th>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr><td>T1</td> <!-- transition -->
|
|
|
|
|
<td>ready</td> <!-- previous state -->
|
|
|
|
|
<td>BYE</td> <!-- input -->
|
|
|
|
|
<td>200 OK</td> <!-- output -->
|
|
|
|
|
<td>terminated</td> <!-- next state -->
|
|
|
|
|
<td>
|
|
|
|
|
When the @b BYE request is received, the recipient terminates the
|
|
|
|
|
currently ongoing @b INVITE transaction, the session and its dialog
|
|
|
|
|
usage (if there is another dialog usage active, e.g., a subscription
|
|
|
|
|
creted by @b REFER.)
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>T2</td> <!-- transition -->
|
|
|
|
|
<td>ready</td> <!-- previous state -->
|
|
|
|
|
<td>nua_bye</td> <!-- input -->
|
|
|
|
|
<td>BYE</td> <!-- output -->
|
|
|
|
|
<td>terminating</td> <!-- next state -->
|
|
|
|
|
<td>
|
|
|
|
|
The application terminates the session by calling nua_bye(). All the
|
|
|
|
|
call-related requests on the dialog are rejected while in
|
|
|
|
|
terminating state with <i>487 No Such Call</i> response.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>T3</td> <!-- transition -->
|
|
|
|
|
<td>terminating</td> <!-- previous state -->
|
|
|
|
|
<td>2XX 3XX 4XX 5XX 6XX</td> <!-- input -->
|
|
|
|
|
<td>-</td> <!-- output -->
|
|
|
|
|
<td>terminated</td> <!-- next state -->
|
|
|
|
|
<td>
|
|
|
|
|
The session is finally terminated when a final response to @b BYE is
|
|
|
|
|
received. Note that nua stack does retry @b BYE requests.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>T4</td> <!-- transition -->
|
|
|
|
|
<td>ready</td> <!-- previous state -->
|
|
|
|
|
<td>"graceful" response</td> <!-- input -->
|
|
|
|
|
<td>BYE</td> <!-- output -->
|
|
|
|
|
<td>terminating</td> <!-- next state -->
|
|
|
|
|
<td>
|
|
|
|
|
A call-related request (@b re-INVITE, @b UPDATE, @b INFO, @b PRACK,
|
|
|
|
|
@b REFER) fails with a response code indicating that the client
|
|
|
|
|
should gracefully terminate the call.
|
|
|
|
|
</td></tr>
|
|
|
|
|
<tr><td>T5</td> <!-- transition -->
|
|
|
|
|
<td>ready</td> <!-- previous state -->
|
|
|
|
|
<td>"fatal" response</td> <!-- input -->
|
|
|
|
|
<td>-</td> <!-- output -->
|
|
|
|
|
<td>terminated</td> <!-- next state -->
|
|
|
|
|
<td>
|
|
|
|
|
A call-related request (@b re-INVITE, @b UPDATE, @b INFO, @b PRACK,
|
|
|
|
|
@b REFER) fails with a response code indicating that the call has
|
|
|
|
|
been terminated.
|
|
|
|
|
</td></tr>
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
@sa http://www.ietf.org/internet-drafts/draft-sparks-sipping-dialogusage-01.txt
|
|
|
|
|
@sa sip_response_terminates_dialog()
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
For reference:
|
|
|
|
|
|
|
|
|
|
+---------------+
|
|
|
|
|
+-(1)--| INIT |-----+
|
|
|
|
|
INVITE/- | +---------------+ (A) INVITE/100
|
|
|
|
|
V |
|
|
|
|
|
+------------+ +------------+
|
|
|
|
|
+----| CALLING | +---| RECEIVED |--+
|
|
|
|
|
| +------------+ | +------------+ |
|
|
|
|
|
| | | | |
|
|
|
|
|
| (2) 18X/- | (B) -/18X |
|
|
|
|
|
| V | V |
|
|
|
|
|
| +------------+ | +------------+ |
|
|
|
|
|
|<---| PROCEEDING |--+ | | EARLY |->|
|
|
|
|
|
| +------------+ | | +------------+ (F) -/[3456]XX
|
|
|
|
|
| : | | | |
|
|
|
|
|
| (4) 2XX/- | (E) -/2XX (C) -/2XX | or
|
|
|
|
|
| V | | V |
|
|
|
|
|
| + - - - - - -+ | | +------------+ (G) CANCEL/200,487
|
|
|
|
|
| : COMPLETING : | +-->| COMPLETE | |
|
|
|
|
|
| + - - - - - -+ | +------------+ |
|
|
|
|
|
| : | | : |
|
|
|
|
|
| (5)-/ACK (3) 2XX/ACK ACK/-(D) : |
|
|
|
|
|
| : | | : |
|
|
|
|
|
| : V | : |
|
|
|
|
|
| : +---------------+ | : |
|
|
|
|
|
| + - - >| READY |<----+ : |
|
|
|
|
|
| +---------------+ : |
|
|
|
|
|
| | | : |
|
|
|
|
|
| BYE/200 (i) (ii) -/BYE timeout/ : |
|
|
|
|
|
| | | BYE (H) |
|
|
|
|
|
| | V : |
|
|
|
|
|
| | +--------------+ : |
|
|
|
|
|
(6) [3456]XX/ACK | | TERMINATING |<- - + |
|
|
|
|
|
| | +--------------+ |
|
|
|
|
|
| | | |
|
|
|
|
|
| | (iii) [23456]XX/- |
|
|
|
|
|
| V V |
|
|
|
|
|
| +---------------+ |
|
|
|
|
|
+---------------->| TERMINATED |<--------------+
|
|
|
|
|
+---------------+
|
|
|
|
|
|
|
|
|
|
|
V
|
|
|
|
|
INIT
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**@page nua_event_diagrams NUA Event Diagrams
|
|
|
|
|
|
|
|
|
|
The example diagrams below try to present how to use NUA API with different
|
|
|
|
|
SIP use cases.
|
|
|
|
|
|
|
|
|
|
@section nua_event_diagram_call Basic Call
|
|
|
|
|
|
|
|
|
|
The SIP following event diagram shows a pretty simple, succesful call case.
|
|
|
|
|
The nua events and nua function calls are show in the diagram below as well
|
|
|
|
|
as the SIP messages.
|
|
|
|
|
|
|
|
|
|
The call setup above assumes parameters NUTAG_AUTOALERT(0),
|
|
|
|
|
NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
|
|
|
|
|
Alice Proxy Bob
|
|
|
|
|
0 | | |
|
|
|
|
|
1 nua_handle() | | |
|
|
|
|
|
2 nua_invite() -> |-----INVITE---->| |
|
|
|
|
|
3 nua_i_state <- | | |
|
|
|
|
|
4 | |-----INVITE---->| -> nua_i_invite
|
|
|
|
|
5 |<--100 Trying---| | -> nua_i_state
|
|
|
|
|
6 | | |
|
|
|
|
|
7 | | |
|
|
|
|
|
8 | | |
|
|
|
|
|
9 | |<--180 Ringing--| <- nua_respond(180)
|
|
|
|
|
10 nua_i_invite <- |<--180 Ringing--| | -> nua_i_state
|
|
|
|
|
11 nua_i_state <- | | |
|
|
|
|
|
12 | |<--200 OK-------| <- nua_respond(200)
|
|
|
|
|
13 nua_i_invite <- |<---200 OK------| | -> nua_i_state
|
|
|
|
|
14 nua_i_state <- | | |
|
|
|
|
|
15 nua_ack() -> |-----ACK------->| |
|
|
|
|
|
16 nua_i_state <- | |-----ACK------->| -> nua_i_ack
|
|
|
|
|
17 | | | -> nua_i_state
|
|
|
|
|
18 | | |
|
|
|
|
|
19 <<====== SIP Session Established =======>>
|
|
|
|
|
20 | | |
|
|
|
|
|
21 | | |
|
|
|
|
|
22 nua_bye() -> |-----BYE------->| |
|
|
|
|
|
23 | |-----BYE------->| -> nua_i_bye
|
|
|
|
|
24 | |<----200 OK-----| -> nua_i_state
|
|
|
|
|
25 nua_r_bye <- |<---200 OK------| |
|
|
|
|
|
26 nua_i_state <- | | |
|
|
|
|
|
| | |
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
@section nua_event_diagram_call_hold Holding Call
|
|
|
|
|
|
|
|
|
|
The media (audio, video) can be put on hold. In SIP system this means that
|
|
|
|
|
application can indicate to the remote end that it is engaged in other
|
|
|
|
|
activity (another call, for instance) and does not wish to receive media
|
|
|
|
|
from the remove end.
|
|
|
|
|
|
|
|
|
|
The call hold is usully implemented using re-INVITE. Re-INVITE is an INVITE
|
|
|
|
|
request sent on existing SIP session. Both original caller and callee can
|
|
|
|
|
send re-INVITEs. The main use of re-INVITE is modifying sessions: adding
|
|
|
|
|
media lines to the session, changing codecs on existing media, and, as you
|
|
|
|
|
might expect, putting existing media on hold as well as resuming media from
|
|
|
|
|
hold.
|
|
|
|
|
|
|
|
|
|
A re-INVITE is sent by calling nua_invite() on handle with existing call.
|
|
|
|
|
When putting call on hold, the application can include SOATAG_HOLD("audio")
|
|
|
|
|
or SOATAG_HOLD("video") or SOATAG_HOLD("audio, video") or SOATAG_HOLD("*")
|
|
|
|
|
as parameters to re-INVITE nua_invite(). (Note that last SOATAG_HOLD() in
|
|
|
|
|
the tag list will override the SOATAG_HOLD() tags before it.)
|
|
|
|
|
|
|
|
|
|
Another feature where nua tries to be helpful is autoanswer and auto-ACK on
|
|
|
|
|
existing sessions: the re-INVITE is automatically responded with <i>200 OK</i>
|
|
|
|
|
and ACK is automatically sent. (If the application wants to respond and ACK
|
|
|
|
|
by itself, it should explicitly set NUTAG_AUTOANSWER(0) and/or
|
|
|
|
|
NUTAG_AUTOACK(0) in the handle; either include them in nua_invite() or
|
|
|
|
|
nua_respond() parameters or call nua_set_hparams() explicitly.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
Alice Proxy Bob
|
|
|
|
|
0 nua_handle() | | |
|
|
|
|
|
1 | | |
|
|
|
|
|
2 nua_invite() -> |-----INVITE---->| |
|
|
|
|
|
3 nua_i_state <- | | |
|
|
|
|
|
4 | |-----INVITE---->| -> nua_i_invite
|
|
|
|
|
5 |<--100 Trying---| | -> nua_i_state
|
|
|
|
|
6 | | |
|
|
|
|
|
7 | | |
|
|
|
|
|
8 | | |
|
|
|
|
|
9 | |<--180 Ringing--| <- nua_respond(180)
|
|
|
|
|
10 nua_i_invite <- |<--180 Ringing--| | -> nua_i_state
|
|
|
|
|
11 nua_i_state <- | | |
|
|
|
|
|
12 | |<--200 OK-------| <- nua_respond(200)
|
|
|
|
|
13 nua_i_invite <- |<---200 OK------| | -> nua_i_state
|
|
|
|
|
14 nua_i_state <- | | |
|
|
|
|
|
15 nua_ack() -> |-----ACK------->| |
|
|
|
|
|
16 nua_i_state <- | |-----ACK------->| -> nua_i_ack
|
|
|
|
|
17 | | | -> nua_i_state
|
|
|
|
|
18 | | |
|
|
|
|
|
19 <<== Bi-Directional RTP Established ==>>
|
|
|
|
|
20 | | |
|
|
|
|
|
21 | | |
|
|
|
|
|
22 | |<--INVITE(hold)-| <- nua_invite(..
|
|
|
|
|
21 | | | NUTAG_HOLD("*")..)
|
|
|
|
|
23 nua_i_invite <- |<-INVITE(hold)--| | -> nua_i_state
|
|
|
|
|
25 nua_i_state <- |----200 OK----->| |
|
|
|
|
|
26 | |----200 OK----->| -> nua_i_invite
|
|
|
|
|
28 | |<-----ACK-------| -> nua_i_state
|
|
|
|
|
29 nua_i_ack <- |<----ACK--------| |
|
|
|
|
|
24 | | |
|
|
|
|
|
30 <<== Uni-Directional RTP Established ==>>
|
|
|
|
|
24 | | |
|
|
|
|
|
31 | | |
|
|
|
|
|
32 | |<--INVITE-------| <- nua_invite(..
|
|
|
|
|
21 | | | NUTAG_HOLD(NULL)..)
|
|
|
|
|
33 nua_i_invite <- |<--INVITE-------| | -> nua_i_state
|
|
|
|
|
35 nua_i_state <- |---200 OK------>| |
|
|
|
|
|
36 | |---200 OK------>| -> nua_i_invite
|
|
|
|
|
38 | |<----ACK--------| -> nua_i_state
|
|
|
|
|
39 nua_i_ack <- |<----ACK--------| |
|
|
|
|
|
40 nua_i_state <- | | |
|
|
|
|
|
19 <<== Bi-Directional RTP Established ==>>
|
|
|
|
|
42 | | |
|
|
|
|
|
43 nua_bye() -> |-----BYE------->| |
|
|
|
|
|
44 nua_i_state <- | |-----BYE------->| -> nua_i_bye
|
|
|
|
|
46 | |<----200 OK-----| -> nua_i_state
|
|
|
|
|
47 |<---200 OK------| |
|
|
|
|
|
| | |
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@section nua_event_diagram_call_transfer Call Transfer
|
|
|
|
|
|
|
|
|
|
This is the unattended call transfer case.
|
|
|
|
|
|
|
|
|
|
1st MSC showing Alice's end:
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
Alice Bob Carol
|
|
|
|
|
0 | | |
|
|
|
|
|
1 nua_i_invite <- |<-----INVITE--------| |
|
|
|
|
|
2 nua_i_state <- | | |
|
|
|
|
|
2 | | |
|
|
|
|
|
3 nua_respond(180) -> |----180 Ringing---->| |
|
|
|
|
|
2 nua_i_state <- | | |
|
|
|
|
|
4 | | |
|
|
|
|
|
5 nua_respond(200) -> |------200 OK------->| |
|
|
|
|
|
6 nua_i_state <- | | |
|
|
|
|
|
8 | | |
|
|
|
|
|
7 nua_i_ack <- |<-------ACK---------| |
|
|
|
|
|
8 nua_i_state <- | | |
|
|
|
|
|
9 |<========RTP=======>| |
|
|
|
|
|
10 | | |
|
|
|
|
|
11 << Alice performs unattended transfer >> |
|
|
|
|
|
12 | | |
|
|
|
|
|
13 | | |
|
|
|
|
|
14 nua_refer() -> |---REFER("r: C")--->| |
|
|
|
|
|
15 | | |
|
|
|
|
|
16 nua_r_refer <- |<---202 Accepted----| |
|
|
|
|
|
17 | | |
|
|
|
|
|
18 nua_i_notify <- |<-----NOTIFY--------| |
|
|
|
|
|
19 | | |
|
|
|
|
|
20 |------200 OK------->| |
|
|
|
|
|
21 | |---INVITE("b: A")-->|
|
|
|
|
|
23 | | |
|
|
|
|
|
22 nua_bye() -> |-------BYE--------->| |
|
|
|
|
|
23 | | |
|
|
|
|
|
24 nua_r_bye <- |<----200 OK---------| |
|
|
|
|
|
25 nua_i_state <- | No RTP Session | |
|
|
|
|
|
28 | |<----180 Ringing----|
|
|
|
|
|
26 nua_i_notify <- |<- - -NOTIFY - - - -| |
|
|
|
|
|
27 | | |
|
|
|
|
|
20 |- - - 200 OK- - - ->| |
|
|
|
|
|
29 | | |
|
|
|
|
|
30 | |<------200 OK-------|
|
|
|
|
|
31 | | |
|
|
|
|
|
32 | |---------ACK------->|
|
|
|
|
|
33 | | RTP |
|
|
|
|
|
34 | |<==================>|
|
|
|
|
|
35 | | |
|
|
|
|
|
36 |<-----NOTIFY--------| |
|
|
|
|
|
37 | | |
|
|
|
|
|
38 |------200 OK------->| |
|
|
|
|
|
| | |
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
2nd MSC showing Bobs's end:
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
Alice Bob (nh1) Bob (nh2) Carol
|
|
|
|
|
0 | | | |
|
|
|
|
|
1 |<-----INVITE--------| | |
|
|
|
|
|
2 | | | |
|
|
|
|
|
3 |---180 Ringing----->| | |
|
|
|
|
|
4 | | | |
|
|
|
|
|
5 |------200 OK------->| | |
|
|
|
|
|
6 | | | |
|
|
|
|
|
7 |<-------ACK---------| | |
|
|
|
|
|
8 | RTP | | |
|
|
|
|
|
9 |<==================>| | |
|
|
|
|
|
10 | | | |
|
|
|
|
|
11<< Alice performs unattended transfer >> | |
|
|
|
|
|
12 | | | |
|
|
|
|
|
13 | Refer-To:C F5| | |
|
|
|
|
|
14 |-REFER------------->| -> nua_i_refer | |
|
|
|
|
|
15 | | | |
|
|
|
|
|
16 |<-202 Accepted------| | |
|
|
|
|
|
17 | | | |
|
|
|
|
|
18 |<-----NOTIFY--------| | |
|
|
|
|
|
19 | | | |
|
|
|
|
|
20 |------200 OK------->| -> nua_r_notify | |
|
|
|
|
|
21 | | | |
|
|
|
|
|
22 |-------BYE--------->| -> nua_i_bye | |
|
|
|
|
|
23 | | -> nua_i_state | |
|
|
|
|
|
24 |<----200 OK---------| nua_handle() -> | |
|
|
|
|
|
25 | No RTP Session | nua_invite() -> | |
|
|
|
|
|
26 | | |--INVITE("b: A")--->|
|
|
|
|
|
27 | | | |
|
|
|
|
|
28 | | nua_i_invite <- |<--180 Ringing------|
|
|
|
|
|
29 | | nua_i_state <- | |
|
|
|
|
|
30 | | nua_i_invite <- |<----200 OK---------|
|
|
|
|
|
31 | | nua_i_state <- | |
|
|
|
|
|
32 | | nua_ack -> |-------ACK--------->|
|
|
|
|
|
33 | | | |
|
|
|
|
|
34 | | |<=======RTP========>|
|
|
|
|
|
35 | | | |
|
|
|
|
|
36 |<-----NOTIFY--------| | |
|
|
|
|
|
37 | |
|
|
|
|
|
38 |------200 OK------->| -> nua_r_notify
|
|
|
|
|
39 | | <- nua_handle_destroy
|
|
|
|
|
| |
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
Bob includes nh1 in nua_invite()/25 as NUTAG_NOTIFY_REFER() parameter.
|
|
|
|
|
|
|
|
|
|
Open Issue 1:
|
|
|
|
|
|
|
|
|
|
- how Bob know when to destroy nh1?
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@section nua_event_diagram_3gpp_call 3GPP Call Model
|
|
|
|
|
|
|
|
|
|
The 3GPP call model is defined in 3GPP TS 24.229. In order to select only a
|
|
|
|
|
single codec and ensure that the QoS reservationa are made before the call
|
|
|
|
|
is alerting, the 3GPP call model employs multiple offer/answer exchanges. It
|
|
|
|
|
uses 100rel and PRACK (@RFC3262), UPDATE (@RFC3311) and preconditions
|
|
|
|
|
(@RFC3312) extensions specified by IETF.
|
|
|
|
|
|
|
|
|
|
The call setup below assumes parameters NUTAG_AUTOALERT(0),
|
|
|
|
|
NUTAG_AUTOANSWER(0) on B side, NUTAG_AUTOACK(0) on A side.
|
|
|
|
|
|
|
|
|
|
@code
|
|
|
|
|
A B
|
|
|
|
|
0 nua_handle() | |
|
|
|
|
|
1 nua_invite() -> | |
|
|
|
|
|
2 nua_i_state <- |----INVITE (offer)---->|
|
|
|
|
|
3 | | -> nua_i_invite
|
|
|
|
|
4 | | -> nua_i_state
|
|
|
|
|
5 | |
|
|
|
|
|
6 | | <- nua_respond(183)
|
|
|
|
|
7 nua_i_invite <- |<----183 (answer)------| -> nua_i_state
|
|
|
|
|
8 nua_i_state <- | |
|
|
|
|
|
9 << single codec is selected now >>
|
|
|
|
|
10 |-----PRACK(offer2)---->| -> nua_i_prack
|
|
|
|
|
11 | | -> nua_i_state
|
|
|
|
|
12 nua_r_prack <- |<--200/PRACK(answer2)--|
|
|
|
|
|
13 | |
|
|
|
|
|
14 | |
|
|
|
|
|
15 << resource reservations are done now >>
|
|
|
|
|
16 | |
|
|
|
|
|
17 nua_update() -> |----UPDATE (offer3)--->|
|
|
|
|
|
18 nua_i_state <- | |
|
|
|
|
|
19 nua_i_state <- |<-200/UPDATE (answer3)-| -> nua_i_update
|
|
|
|
|
20 | | -> nua_i_state
|
|
|
|
|
21 | |
|
|
|
|
|
22 | | << B rings >>
|
|
|
|
|
23 | |
|
|
|
|
|
24 | | <- nua_respond(180)
|
|
|
|
|
25 nua_i_invite <- |<---------180----------|
|
|
|
|
|
26 nua_i_state <- | |
|
|
|
|
|
27 |--------PRACK--------->| -> nua_i_prack
|
|
|
|
|
28 nua_r_prack <- |<-----200/PRACK------->| -> nua_i_state
|
|
|
|
|
29 | |
|
|
|
|
|
30 | | <- nua_respond(200)
|
|
|
|
|
31 nua_i_invite <- |<---------200----------| -> nua_i_state
|
|
|
|
|
32 nua_i_state <- | |
|
|
|
|
|
33 nua_ack() -> | |
|
|
|
|
|
34 nua_i_state <- |----------ACK--------->| -> nua_i_ack
|
|
|
|
|
35 | | -> nua_i_state
|
|
|
|
|
| |
|
|
|
|
|
@endcode
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**@var nua_event_e
|
|
|
|
|
*
|
|
|
|
|
* @brief Events
|
|
|
|
|
*
|
|
|
|
|
* The NUA event loop calls an event callback function when an application
|
|
|
|
|
* needs to act on something that happened in the Sofia stack. The callback
|
|
|
|
|
* function is registered when nua_create() function call is used to create
|
|
|
|
|
* the NUA stack object.
|
|
|
|
|
*
|
|
|
|
|
* The prototype of the event callback function is:
|
|
|
|
|
* @code
|
|
|
|
|
* void nua_callback_f(nua_event_t event,
|
|
|
|
|
* int status,
|
|
|
|
|
* char const *phrase,
|
|
|
|
|
* nua_t *nua,
|
|
|
|
|
* nua_magic_t *magic,
|
|
|
|
|
* nua_handle_t *nh,
|
|
|
|
|
* nua_hmagic_t *hmagic,
|
|
|
|
|
* sip_t const *sip,
|
|
|
|
|
* tagi_t tags[]);
|
|
|
|
|
* @endcode
|
|
|
|
|
*
|
|
|
|
|
* @param event Callback event identification. \n
|
|
|
|
|
* Always present
|
|
|
|
|
* @param status Protocol status code. \n
|
|
|
|
|
* Always present
|
|
|
|
|
* @param phrase Text corresponding to status code. \n
|
|
|
|
|
* Always present
|
|
|
|
|
* @param nua Pointer to NUA stack object. \n
|
|
|
|
|
* Always present
|
|
|
|
|
* @param magic Pointer to callback context from nua_create(). \n
|
|
|
|
|
* Always present
|
|
|
|
|
* @param nh Pointer to operation handle.
|
|
|
|
|
* @param hmagic Pointer to callback context from nua_handle().
|
2007-04-15 02:03:41 +00:00
|
|
|
|
* @param sip Headers in parsed incoming message. May be NULL.
|
|
|
|
|
* See also nua_current_request().
|
2006-12-21 06:30:28 +00:00
|
|
|
|
* @param tags Tag list containing more information about the state of NUA.
|
|
|
|
|
* May be empty.
|
|
|
|
|
*
|
|
|
|
|
* Note that the contents of the last four parameters vary depending on
|
|
|
|
|
* the event. The descriptions can be found from the description of the
|
|
|
|
|
* individual event.
|
|
|
|
|
*
|
|
|
|
|
* The events can be divided into the following categories: \n
|
2007-04-15 02:03:41 +00:00
|
|
|
|
* @par Status or Error Indications:
|
2006-12-21 06:30:28 +00:00
|
|
|
|
* #nua_i_active \n
|
2007-04-15 02:03:41 +00:00
|
|
|
|
* #nua_i_error \n
|
|
|
|
|
* #nua_i_fork \n
|
|
|
|
|
* #nua_i_media_error \n
|
|
|
|
|
* #nua_i_subscription \n
|
|
|
|
|
* #nua_i_state \n
|
|
|
|
|
* #nua_i_terminated
|
|
|
|
|
*
|
|
|
|
|
* @par SIP requests:
|
2006-12-21 06:30:28 +00:00
|
|
|
|
* #nua_i_ack \n
|
|
|
|
|
* #nua_i_bye \n
|
|
|
|
|
* #nua_i_cancel \n
|
|
|
|
|
* #nua_i_chat \n
|
|
|
|
|
* #nua_i_info \n
|
|
|
|
|
* #nua_i_invite \n
|
|
|
|
|
* #nua_i_message \n
|
|
|
|
|
* #nua_i_method \n
|
|
|
|
|
* #nua_i_notify \n
|
|
|
|
|
* #nua_i_options \n
|
|
|
|
|
* #nua_i_prack \n
|
|
|
|
|
* #nua_i_publish \n
|
|
|
|
|
* #nua_i_refer \n
|
|
|
|
|
* #nua_i_register \n
|
|
|
|
|
* #nua_i_subscribe \n
|
|
|
|
|
* #nua_i_update
|
|
|
|
|
*
|
|
|
|
|
* @par Responses:
|
|
|
|
|
* #nua_r_get_params \n
|
|
|
|
|
* #nua_r_notifier \n
|
|
|
|
|
* #nua_r_shutdown \n
|
|
|
|
|
* #nua_r_terminate
|
|
|
|
|
*
|
|
|
|
|
* @par SIP responses:
|
|
|
|
|
* #nua_r_bye \n
|
|
|
|
|
* #nua_r_cancel \n
|
|
|
|
|
* #nua_r_info \n
|
|
|
|
|
* #nua_r_invite \n
|
|
|
|
|
* #nua_r_message \n
|
|
|
|
|
* #nua_r_notify \n
|
|
|
|
|
* #nua_r_options \n
|
|
|
|
|
* #nua_r_prack \n
|
|
|
|
|
* #nua_r_publish \n
|
|
|
|
|
* #nua_r_refer \n
|
|
|
|
|
* #nua_r_register \n
|
|
|
|
|
* #nua_r_subscribe \n
|
|
|
|
|
* #nua_r_unpublish \n
|
|
|
|
|
* #nua_r_unregister \n
|
|
|
|
|
* #nua_r_unsubscribe \n
|
|
|
|
|
* #nua_r_update
|
2007-08-06 19:24:10 +00:00
|
|
|
|
*
|
|
|
|
|
* @sa nua_event_is_incoming_request(), nua_event_name()
|
2006-12-21 06:30:28 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_i_chat
|
|
|
|
|
*
|
|
|
|
|
* Incoming chat message.
|
|
|
|
|
*
|
|
|
|
|
* @param nh operation handle associated with the message
|
|
|
|
|
* @param hmagic operation magic associated with the handle
|
|
|
|
|
* @param sip incoming chat message
|
|
|
|
|
* @param tags empty
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_i_error
|
|
|
|
|
*
|
|
|
|
|
* Error indication.
|
|
|
|
|
*
|
|
|
|
|
* Will be sent when an internal error happened or
|
|
|
|
|
* an error occurred while responding a request.
|
|
|
|
|
*
|
|
|
|
|
* @param status SIP status code or NUA status code (>= 900)
|
|
|
|
|
* describing the problem
|
|
|
|
|
* @param phrase a short textual description of @a status code
|
|
|
|
|
* @param nh NULL or operation handle associated with the call
|
|
|
|
|
* @param hmagic NULL or operation magic associated with the call
|
|
|
|
|
* @param sip NULL
|
|
|
|
|
* @param tags empty or error specific information
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_i_fork
|
|
|
|
|
*
|
|
|
|
|
* Outgoing call has been forked.
|
|
|
|
|
*
|
2007-04-15 02:03:41 +00:00
|
|
|
|
* This is sent when an INVITE request is answered with multiple 2XX series
|
|
|
|
|
* responses.
|
2006-12-21 06:30:28 +00:00
|
|
|
|
*
|
|
|
|
|
* @param status response status code
|
|
|
|
|
* @param phrase a short textual description of @a status code
|
|
|
|
|
* @param nh operation handle associated with the original call
|
|
|
|
|
* @param hmagic operation magic associated with the original call
|
|
|
|
|
* @param sip preliminary or 2XX response to INVITE
|
|
|
|
|
* @param tags NUTAG_HANDLE() of the new forked call
|
|
|
|
|
*
|
|
|
|
|
* @sa #nua_r_invite, #nua_i_state, @ref nua_call_model
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_i_media_error
|
|
|
|
|
*
|
|
|
|
|
* Media error indication.
|
|
|
|
|
*
|
|
|
|
|
* This may be sent after an SOA operation has failed while processing
|
|
|
|
|
* incoming or outgoing call.
|
|
|
|
|
*
|
|
|
|
|
* @param status SIP status code or NUA status code (>= 900)
|
|
|
|
|
* describing the problem
|
|
|
|
|
* @param phrase a short textual description of @a status code
|
|
|
|
|
* @param nh operation handle associated with the call
|
|
|
|
|
* @param hmagic operation magic associated with this handle
|
|
|
|
|
* (maybe NULL if call handle was created for this call)
|
|
|
|
|
* @param sip NULL
|
|
|
|
|
* @param tags empty
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* nua_i_message is documented with nua_stack_process_message() */
|
|
|
|
|
|
|
|
|
|
/* nua_i_method is documented with nua_stack_process_method() */
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_i_network_changed
|
|
|
|
|
*
|
|
|
|
|
* Local IP(v6) address has changed.
|
|
|
|
|
*
|
|
|
|
|
* @param nh default operation handle
|
|
|
|
|
* @param hmagic operation magic associated with the default operation handle
|
|
|
|
|
* @param sip NULL
|
|
|
|
|
* @param tags empty
|
|
|
|
|
*
|
|
|
|
|
* @since Experimental in @VERSION_1_12_2.
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* nua_i_notify is documented with nua_stack_process_notify() */
|
|
|
|
|
|
|
|
|
|
/* nua_i_options is documented with nua_stack_process_options() */
|
|
|
|
|
|
|
|
|
|
/* nua_i_publish is documented with nua_stack_process_publish() */
|
|
|
|
|
|
|
|
|
|
/* nua_i_refer is documented with nua_stack_process_refer() */
|
|
|
|
|
|
|
|
|
|
/* nua_i_subscribe is documented with nua_stack_process_subscribe() */
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_i_subscription
|
|
|
|
|
*
|
|
|
|
|
* Incoming subscription to be authorized.
|
|
|
|
|
*
|
|
|
|
|
* This event is launched by nua_notifier() to inform application of the
|
|
|
|
|
* current state of the subscriber. The subscriber state is included in the
|
|
|
|
|
* NUTAG_SUBSTATE() tag. If the state is #nua_substate_pending or
|
|
|
|
|
* #nua_substate_embryonic, application should to authorize the subscriber
|
|
|
|
|
* with nua_authorize().
|
|
|
|
|
*
|
|
|
|
|
* @param nh operation handle associated with the notifier
|
|
|
|
|
* @param hmagic operation magic
|
|
|
|
|
* @param status statuscode of response sent automatically by stack
|
|
|
|
|
* @param sip incoming SUBSCRIBE request
|
|
|
|
|
* @param tags NEATAG_SUB(),
|
|
|
|
|
* NUTAG_SUBSTATE()
|
|
|
|
|
*
|
|
|
|
|
* @sa nua_notifier(), #nua_i_subscribe, nua_authorize(), nua_terminate()
|
|
|
|
|
* @RFC3265
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* nua_i_update is documented with nua_stack_process_update() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_bye is documented with process_response_to_bye() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_cancel is documented with process_response_to_cancel() */
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_r_chat
|
|
|
|
|
*
|
|
|
|
|
* Answer to outgoing chat message.
|
|
|
|
|
*
|
|
|
|
|
* @param nh operation handle associated with the notifier
|
|
|
|
|
* @param hmagic operation magic associated with the notifier
|
|
|
|
|
* @param sip response to MESSAGE request or NULL upon an error
|
2007-04-15 02:03:41 +00:00
|
|
|
|
* (error code and message are in status and phrase parameters)
|
2006-12-21 06:30:28 +00:00
|
|
|
|
* @param tags empty
|
|
|
|
|
*
|
|
|
|
|
* @sa nua_chat(), #nua_r_message
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* nua_r_info is documented with process_response_to_info() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_invite is documented with process_response_to_invite() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_message is documented with process_response_to_message() */
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_r_notifier
|
|
|
|
|
*
|
|
|
|
|
* Answer to nua_notitier()
|
|
|
|
|
*
|
|
|
|
|
* @param nh operation handle associated with the call
|
|
|
|
|
* @param hmagic operation magic associated with the call
|
|
|
|
|
* @param sip NULL
|
|
|
|
|
* @param tags SIPTAG_EVENT() \n
|
|
|
|
|
* SIPTAG_CONTENT_TYPE()
|
|
|
|
|
*
|
|
|
|
|
* @sa nua_notitier(), #nua_i_subscription, @RFC3265
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* nua_r_notify is documented with process_response_to_notify() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_options is documented with process_response_to_options() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_prack is documented with process_response_to_prack() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_publish is documented with process_response_to_publish() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_refer is documented with process_response_to_refer() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_shutdown is documented with nua_stack_shutdown() */
|
|
|
|
|
|
|
|
|
|
/* nua_r_subscribe is documented with process_response_to_subscribe() */
|
|
|
|
|
|
|
|
|
|
/** @NUA_EVENT nua_r_terminate
|
|
|
|
|
*
|
|
|
|
|
* Answer to nua_terminate().
|
|
|
|
|
*
|
|
|
|
|
* @param nh operation handle associated with the notifier
|
|
|
|
|
* @param hmagic operation magic associated with the notifier
|
|
|
|
|
* @param sip NULL
|
|
|
|
|
* @param tags empty
|
|
|
|
|
*
|
|
|
|
|
* @sa nua_terminate(), nua_handle_destroy()
|
|
|
|
|
*
|
|
|
|
|
* @END_NUA_EVENT
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* nua_r_unsubscribe is documented with process_response_to_subscribe() */
|