diff --git a/content/documentation/api.html b/content/documentation/api.html index 9bf0d64..92bc801 100644 --- a/content/documentation/api.html +++ b/content/documentation/api.html @@ -20,6 +20,8 @@ * Class <%= my_lib_link_to "api/uri" %> * Class <%= my_lib_link_to "api/nameAddrHeader" %> * Class <%= my_lib_link_to "api/refer_subscriber" %> +* Class <%= my_lib_link_to "api/subscriber" %> +* Class <%= my_lib_link_to "api/notifier" %> * <%= my_lib_link_to "api/node_websocket" %> * <%= my_lib_link_to "api/ua_configuration_parameters" %> * <%= my_lib_link_to "api/events" %> diff --git a/content/documentation/api/notifier.html b/content/documentation/api/notifier.html new file mode 100644 index 0000000..91c3469 --- /dev/null +++ b/content/documentation/api/notifier.html @@ -0,0 +1,157 @@ +--- +title: JsSIP.Notifier +link_text: "@JsSIP.Notifier@" +--- + +h1. Class @JsSIP.Notifier@ + +The class @JsSIP.Notifier@ represents a NOTIFY dialog. +The dialog receive sequence of SUBSCRIBE messages and send NOTIFY messages. + +* <%= link_to "Instance Attributes", "#section_attributes" %> +** <%= link_to "state", "#attribute_state" %> +** <%= link_to "id", "#attribute_id" %> +** <%= link_to "data", "#attribute_data" %> +* <%= link_to "Instance Methods", "#section_methods" %> +** <%= link_to "start()", "#method_start" %> +** <%= link_to "setActiveState()", "#method_setActiveState" %> +** <%= link_to "notify()", "#method_notify" %> +** <%= link_to "terminate()", "#method_terminate" %> +* <%= link_to "Events", "#section_events" %> +** <%= link_to "subscribe", "#event_subscribe" %> +** <%= link_to "terminated", "#event_terminated" %> + +h2(#section_attributes). Instance Attributes + +h3(#attribute_state). <%= my_lib_api_method 'state' %> + +@number@ The notifier dialog state. + +h4(#notifier_dialog_states). Notifier states + +|_.Constant|_.Value|_.Description| +|@STATE_PENDING@|0|Send NOTIFY with Subscription-State: pending| +|@STATE_ACTIVE@|1|Send NOTIFY with Subscription-State: active| +|@STATE_TERMINATED@|2|Send NOTIFY with Subscription-State: terminated| + +h3(#attribute_id). <%= my_lib_api_method 'id' %> + +The Dialog id structure {@call_id@, @local_tag@, @remote_tag@} associated to this session. + + +h3(#attribute_data). <%= my_lib_api_method 'data' %> + +Custom session empty @Object@ for application usage. The developer can add here custom attribute/value pairs. + +h2(#section_methods). Instance Methods + + +h3(#method_start). <%= my_lib_api_method 'start()' %> + +Please call after creating the Notifier instance and setting the event handlers. + +h3(#method_setActiveState). <%= my_lib_api_method 'setActiveState()' %> + +Switch pending dialog state to active. + +h3(#method_notify). <%= my_lib_api_method 'notify(body)' %> + +Send the initial and subsequent notify request. + +<%= my_lib_api_parameters({ + "body" => "Optional @String@ String representing the body of the NOTIFY." + }) %> + +h4. Example + +CODE_BEGIN "javascript" + + let body = JSON.stringify({ temperature: 18, precipitation: 6, wind: 12 }); + notifier.notify(body); + +CODE_END + +h3(#method_terminate). <%= my_lib_api_method 'terminate(body, reason,retryAfter)' %> + +Terminate. (Send the final NOTIFY request). + +<%= my_lib_api_parameters({ + "body" => "Optional @String@ String representing the body of the NOTIFY.", + "reason" => "Optional @String@ parameter of header Subscription-State", + "retryAfter" => "Optional @Number@ parameter of header Subsription-State" + }) %> + +h2(#section_events). Events + +@JsSIP.Notifier@ class defines a series of events. Each of them allow callback functions registration in order to let the user execute a function for each given stimulus. + +h3(#event_subscribe). @subscribe@ + +Fired when receive SUBSCRIBE (includes initial SUBSCRIBE) + +h4. Parameters + +<%= my_lib_api_parameters({ + "isUnsubscribe" => "@Boolean@ If receive SUBSCRIBE with Expires value 0.", + "subscribe" => "#{my_lib_link_to "incomingRequest"} instance representing the incoming SUBSCRIBE SIP message.", + "body" => "String representing the SIP message body", + "contentType" => "@String@ representing the SIP SUBSCRIBE message Content-Type header field value." +}) %> + +h4. Example + +CODE_BEGIN "javascript" + +notifier.on('subscribe', function(isUnsubscribe, subscribe, body, contentType) +{ + if (isUnsubscribe) + { + notifier.terminate(); + } + else + { + notifier.notify({ temperature: 14 }); + } +}); + +CODE_END + +h3(#event_terminated). @terminated@ + +Fired when Notifier dialog is terminated. + +h4. Parameters + +<%= my_lib_api_parameters({ + "terminationCode" => "@Number@ Termination code. See below.", + "sendFinalNotify" => "@Boolean@ If need send final NOTIFY. @true@ only for case when subscription is expires" +}) %> + + +h4(#subscription_dialog_termination_codes). Subscriber termination codes + +|_.Constant|_.Value|_.Description| +|@NOTIFY_RESPONSE_TIMEOUT@|0|NOTIFY transaction response timeout.| +|@NOTIFY_TRANSPORT_ERROR@|1|NOTIFY transaction transport error.| +|@NOTIFY_NON_OK_RESPONSE@|2|Receive error response code.| +|@NOTIFY_FAILED_AUTHENTICATION@|3|NOTIFY Authentication failure.| +|@SEND_FINAL_NOTIFY@|4|Send NOTIFY with Subscription-State: terminated.| +|@RECEIVE_UNSUBSCRIBE@|5|Receive SUBSCRIBE with Expires: 0| +|@SUBSCRIPTION_EXPIRED@|6|Subscription is expired.| + +h4. Example + +CODE_BEGIN "javascript" + +notifier.on('terminated', function(terminationCode, sendFinalNotify) +{ + console.log('notifier: fired terminated event') + if (sendFinalNotify) + { + // Can be with or without body. + // reason must be "timeout" for the case. + notifier.terminate(null, "timeout"); + } +}); + +CODE_END diff --git a/content/documentation/api/subscriber.html b/content/documentation/api/subscriber.html new file mode 100644 index 0000000..63c662e --- /dev/null +++ b/content/documentation/api/subscriber.html @@ -0,0 +1,174 @@ +--- +title: JsSIP.Subscriber +link_text: "@JsSIP.Subscriber@" +--- + +h1. Class @JsSIP.Subsciber@ + +The class @JsSIP.Subscriber@ represents a SUBSCRIBE dialog. +The dialog send sequence of SUBSCRIBE messages and receive NOTIFY messages. + +* <%= link_to "Instance Attributes", "#section_attributes" %> +** <%= link_to "state", "#attribute_state" %> +** <%= link_to "id", "#attribute_id" %> +** <%= link_to "data", "#attribute_data" %> +* <%= link_to "Instance Methods", "#section_methods" %> +** <%= link_to "subscribe()", "#method_subscribe" %> +** <%= link_to "terminate()", "#method_terminate" %> +* <%= link_to "Events", "#section_events" %> +** <%= link_to "accepted", "#event_accepted" %> +** <%= link_to "pending", "#event_pending" %> +** <%= link_to "active", "#event_active" %> +** <%= link_to "notify", "#event_notify" %> +** <%= link_to "terminated", "#event_terminated" %> + + +h2(#section_attributes). Instance Attributes + + +h3(#attribute_state). <%= my_lib_api_method 'state' %> + +@number@ The subscription dialog state. + +h4(#subscription_dialog_states). Subscriber states + +|_.Constant|_.Value|_.Description| +|@STATE_PENDING@|0|Received NOTIFY with Subscription-State: pending| +|@STATE_ACTIVE@|1|Recevied NOTIFY with Subscription-State: active| +|@STATE_TERMINATED@|2|Received NOTIFY with Subscription-State: terminated| +|@STATE_INIT@|3|This is state after creation.| +|@STATE_NOTIFY_WAIT@|4|This is the state after sending the initial SUBSCRIBE| + + +h3(#attribute_id). <%= my_lib_api_method 'id' %> + +The Dialog id structure {@call_id@, @local_tag@, @remote_tag@} associated to this session. + + +h3(#attribute_data). <%= my_lib_api_method 'data' %> + +Custom session empty @Object@ for application usage. The developer can add here custom attribute/value pairs. + +h2(#section_methods). Instance Methods + + +h3(#method_subscribe). <%= my_lib_api_method 'subscribe(body)' %> + +Send the initial (non-fetch) and subsequent subscribe. + +h4. Parameters + +<%= my_lib_api_parameters({ + "body" => "Optional @String@ String representing the body of the SUBSCRIBE." +}) %> + +h4. Example + +CODE_BEGIN "javascript" + +subscriber.subscribe('Hello'); + +CODE_END + +h3(#method_terminate). <%= my_lib_api_method 'terminate(body)' %> + +Send un-subscribe or fetch-subscribe (with Expires: 0). + +h4. Parameters + +<%= my_lib_api_parameters({ + "body" => "Optional @String@ String representing the body of the SUBSCRIBE." +}) %> + +h4. Example + +CODE_BEGIN "javascript" + +subscriber.terminate(); + +CODE_END + +h2(#section_events). Events + +@JsSIP.Subsciber@ class defines a series of events. Each of them allow callback functions registration in order to let the user execute a function for each given stimulus. + + +h3(#event_accepted). @accepted@ + +Fired once when initial SUBSCRIBE OK received. +Next after initial SUBSCRIBE according specification can be send only after the event + +Note: If you send initial SUBSCRIBE and immediately next SUBSCRIBE. +the next subscribe will be enqueued and send automatically after the event. + +h3(#event_pending). @pending@ + +Fired once when receive NOTIFY with Subscription-State: pending. + +h3(#event_active). @active@ + +Fired once when receive NOTIFY with Subscription-State: active. + +h3(#event_notify). @notify@ + +Fired when receive NOTIFY + +h4. Parameters + +<%= my_lib_api_parameters({ + "isFinal" => "@Boolean@ If receive NOTIFY with Subscription-State: terminated.", + "notify" => "#{my_lib_link_to "incomingRequest"} instance representing the incoming NOTIFY SIP message.", + "body" => "String representing the SIP message body", + "contentType" => "@String@ representing the SIP NOTIFY message Content-Type header field value." +}) %> + + +h4. Example + +CODE_BEGIN "javascript" + +subscriber.on('notify', function(isFinal, notify, body, contentType) +{ + console.log('received NOTIFY', isFinal, body); +}); + +CODE_END + + + +h3(#event_terminated). @terminated@ + +Fired once when receive NOTIFY with Subscription-State: terminated. + +h4. Parameters +(terminationCode, reason, retryAfter) +<%= my_lib_api_parameters({ + "terminatedCode" => "@Number@ terminated code. See below.", + "reason" => "@String@ Value of optional NOTIFY Subscription-State: terminated parameter @reason@", + "retryAfter" => "@Number@ Value of optional NOTIFY Subscription-State: terminated parameter @retry-after@", +}) %> + +h4(#subscription_dialog_termination_codes). Subscriber termination codes + +|_.Constant|_.Value|_.Description| +|@SUBSCRIBE_RESPONSE_TIMEOUT@|0|SUBSCRIBE transaction response timeout| +|@SUBSCRIBE_TRANSPORT_ERROR@|1|SUBSCRIBE transaction transport error| +|@SUBSCRIBE_NON_OK_RESPONSE@|2|SUBSCRIBE transaction response code >= 300| +|@SUBSCRIBE_BAD_OK_RESPONSE@|3|Error during dialog creation using received OK response| +|@SUBSCRIBE_FAILED_AUTHENTICATION@|4|SUBSCRIBE authentication failed| +|@UNSUBSCRIBE_TIMEOUT@|5|Missed response to sent SUBSCRIBE with Exprires: 0| +|@RECEIVE_FINAL_NOTIFY@|6|Received NOTIFY with Subscription-State: terminated| +|@RECEIVE_BAD_NOTIFY@|7|Received NOTIFY without mandatory Subscription-State or Event headers| + + +h4. Example + +CODE_BEGIN "javascript" + +subscriber.on('terminated', function(terminationCode, reason, retryAfter){ + if( terminationCode === subscriber.C.RECEIVE_FINAL_NOTIFY) + { + console.log(`receive final NOTIFY. reason="${reason}" retry-after=${retryAfter}`); + } +}); +CODE_END diff --git a/content/documentation/api/ua.html b/content/documentation/api/ua.html index 65845ba..bf8bcdb 100644 --- a/content/documentation/api/ua.html +++ b/content/documentation/api/ua.html @@ -22,6 +22,8 @@ ** <%= link_to "isConnected()", "#method_isConnected" %> ** <%= link_to "get()", "#method_get" %> ** <%= link_to "set()", "#method_set" %> +** <%= link_to "subscribe()", "#method_subscribe" %> +** <%= link_to "notify()", "#method_notify" %> * <%= link_to "Events", "#section_events" %> ** <%= link_to "connecting", "#event_connecting" %> ** <%= link_to "connected", "#event_connected" %> @@ -34,6 +36,7 @@ ** <%= link_to "newMessage", "#event_newMessage" %> ** <%= link_to "newOptions", "#event_newOptions" %> ** <%= link_to "sipEvent", "#event_sipEvent" %> +** <%= link_to "newSubscribe", "#event_newSubscribe" %> @@ -303,7 +306,115 @@ "value" => "New value." }) %> +h3(#method_subscribe). <%= my_lib_api_method 'subscribe(target, eventName, accept, options)' %> +Create subscriber. <%= my_lib_link_to "subscriber" %> representing the subscriber dialog. +See subscriber definition in RFC 3265 3.1 + +Returns @Object@ + +<%= my_lib_api_parameters({ + "target" => "Destination of the request. @String@ representing a destination username or a complete SIP URI, or a #{my_lib_link_to "uri"} instance.", + "eventName" => "@String@ representing the SUBSCRIBE event name.", + "accept" => "@String@ representing value of Accept header", + "options" => "Optional @Object@ with extra parameters (see below)." +}) %> + +h4. Fields in @options@ Object + +<%= my_lib_api_parameters({ + "expires" => "Optional @Number@ (in seconds) value. Default 900.", + "contentType" => "@String@ representing the content-type of the SUBSCRIBE body.", + "allowEvents" => "Optional @String@ representing Allow-Events header value. See RFC 3265 3.3.7", + "params" => "@Object@ If set will have priority over ua configuration parameters. Can be used: to_uri, to_display_name, from_uri, from_display_name, cseq.", + "extraHeaders" => "Optional @Array@ of @Strings@ with extra SIP headers for each SUBSCRIBE request.", +}) %> + +h4. Example + +CODE_BEGIN "javascript" + +var target = 'alice'; +var eventName = 'foo'; +var accept = 'application/json, plain/text'; +var expires = 600; // in seconds +var contentType = 'application/json' +var params = null; + +/* + Params are optional and are used if domain or from-user differ from those used in REGISTER. + + var params = { + to_uri: new JsSIP.URI('sip', 'alice', 'example.com'), + to_display_name: null, + from_uri: new JsSIP.URI('sip', 'bob', 'example.com'), + from_display_name: null, +} +*/ + +var subscriber; + +try { + subscriber = ua.subscribe( + target, + eventName, + accept, { + expires, + contentType, + params + }); +} catch (e) { + console.log('Error: cannot create subscriber', e); +} + +CODE_END + +h3(#method_notify). <%= my_lib_api_method 'notify(subscribe, contentType, options)' %> + +Create notifier. <%= my_lib_link_to "notifier" %> representing the notifier dialog. +See notifier definition in RFC 3265 3.2 + +Returns @Object@ + +<%= my_lib_api_parameters({ + "subscribe" => "#{my_lib_link_to "incomingRequest"} instance of the received SUBSCRIBE request.", + "contentType" => "@String@ representing the content-type of the NOTIFY body.", + "options" => "Optional @Object@ with extra parameters (see below)." +}) %> + +h4. Fields in @options@ Object + +<%= my_lib_api_parameters({ + "penging" => "Optional @Boolean@ Set initial dialog state as @pending@. Default value is @false@", + "allowEvents" => "Optional @String@ representing Allow-Events header value. See RFC 3265 3.3.7", + "extraHeaders" => "Optional @Array@ of @Strings@ with extra SIP headers for each NOTIFY request.", +}) %> + +h4. Example + +CODE_BEGIN "javascript" + +ua.on('newSubscribe', (e) => { + var subscribe = e.request; + let event = subscribe.parseHeader('event'); + if (event !== 'foo') { // Check that we understand the event. + console.log(`Received SUBSCRIBE with unsupported event ${event}`); + subscribe.reply(489); // "Bad Event" + return; + } + + var contentType = 'application/json'; + var pending = true; + var notifier; + + try { + notifer = ua.notify(subscribe, contentType, { pending }); + } catch(e){ + console.log('Error: cannot create notifier', e); + } +}); + +CODE_END h2(#section_events). Events @@ -486,6 +597,27 @@ }) %> +h4. @event@ parameter + +<%= my_lib_api_parameters({ + "event" => "'event-type' defined in the Event header field.", + "params" => "@Object@ containing the parameters received in the Event header field." +}) %> + + +h3(#event_newSubscribe). newSubscribe + +Fired for an incoming out of dialog SUBSCRIBE request. + + +h4. Event @data@ fields + +<%= my_lib_api_parameters({ + "event" => "@Event@ instance. See below.", + "request" => "#{my_lib_link_to "incomingRequest"} instance of the received SUBSCRIBE request." +}) %> + + h4. @event@ parameter <%= my_lib_api_parameters({